Inter Process Communication - Borular

Boru, iki veya daha fazla ilgili veya birbiriyle ilişkili süreç arasındaki bir iletişim ortamıdır. Ya bir süreç içinde ya da çocuk ile üst süreçler arasında bir iletişim olabilir. İletişim ayrıca ebeveyn, çocuk ve torun arasındaki iletişim gibi çok seviyeli olabilir. İletişim, bir işlemin boruya yazılması ve diğerinin borudan okunmasıyla sağlanır. Boru sistemi çağrısını gerçekleştirmek için, biri dosyaya yazmak ve diğeri dosyadan okumak için iki dosya oluşturun.

Boru mekanizması, boruyla su doldurma, örneğin bir kova gibi gerçek zamanlı bir senaryo ile görüntülenebilir ve birisinin, örneğin bir kupa ile onu geri alması gibi. Doldurma işlemi boruya yazmaktan başka bir şey değildir ve okuma işlemi borudan almaktan başka bir şey değildir. Bu, bir çıktının (su) diğeri (kova) için girdi olduğu anlamına gelir.

#include<unistd.h>

int pipe(int pipedes[2]);

Bu sistem çağrısı, tek yönlü iletişim için bir kanal oluşturacaktır, yani iki tanımlayıcı oluşturur, birincisi borudan okumak için bağlanır ve diğeri boruya yazmak için bağlanır.

Tanımlayıcı pipedes [0] okumak içindir ve pipedes [1] yazmak içindir. Pipedes [1] 'e yazılanlar pipedes [0]' dan okunabilir.

Bu çağrı, başarı durumunda sıfır ve başarısızlık durumunda -1 döndürür. Başarısızlığın nedenini öğrenmek için, errno değişkeni veya perror () işlevi ile kontrol edin.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

Dosya için temel işlemler okuma ve yazma olsa da, işlemleri yapmadan önce dosyayı açmak ve gerekli işlemler tamamlandıktan sonra dosyayı kapatmak önemlidir. Genellikle, varsayılan olarak, sırasıyla 0, 1 ve 2 dosya tanımlayıcılarına sahip giriş (standart giriş - stdin), çıkış (standart çıkış - stdout) ve hata (standart hata - stderr) için kullanılan her işlem için 3 tanımlayıcı açılır.

Bu sistem çağrısı, okuma / yazma / arama (lseek) gibi diğer dosya işlemleri için kullanılan bir dosya tanımlayıcı döndürecektir. Genellikle dosya tanımlayıcıları 3'ten başlar ve açılan dosya sayısı arttıkça bir sayı artar.

Açık sistem çağrısına aktarılan argümanlar yol adı (göreceli veya mutlak yol), dosyanın açılma amacını belirten bayraklardır (örneğin, okumak için açma, O_RDONLY, yazmak, O_WRONLY, okumak ve yazmak için, O_RDWR, mevcut dosyaya eklemek O_APPEND, O_CREAT ile mevcut değilse dosya oluşturmak için) ve kullanıcı veya sahip / grup / diğerleri için okuma / yazma / yürütme izinleri sağlayan gerekli mod. Mod sembollerle belirtilebilir.

Oku - 4, Yaz - 2 ve Yürüt - 1.

Örneğin: Sekizli değer (0 ile başlar), 0764, sahibin okuma, yazma ve yürütme izinlerine sahip olduğu, grubun okuma ve yazma izinlerine sahip olduğu, diğerlerinin okuma izinlerine sahip olduğu anlamına gelir. Bu aynı zamanda S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH, 0700 | 0040 | 0020 | 0004 → 0764'ü ima eder veya çalıştırır.

Başarı durumunda bu sistem çağrısı, hata durumunda yeni dosya tanımlayıcı kimliğini ve -1'i döndürür. Hatanın nedeni, errno değişkeni veya perror () işlevi ile belirlenebilir.

#include<unistd.h>

int close(int fd)

Yukarıdaki sistem çağrısı kapatma zaten açılmış dosya tanımlayıcısı. Bu, dosyanın artık kullanımda olmadığı ve ilişkili kaynakların başka herhangi bir işlem tarafından yeniden kullanılabileceği anlamına gelir. Bu sistem çağrısı başarı durumunda sıfır ve hata durumunda -1 döndürür. Hatanın nedeni, errno değişkeni veya perror () işlevi ile belirlenebilir.

#include<unistd.h>

ssize_t read(int fd, void *buf, size_t count)

Yukarıdaki sistem çağrısı, fd dosya tanımlayıcısının argümanları, ayrılmış belleğe sahip uygun tampon (statik veya dinamik) ve tampon boyutuyla belirtilen dosyadan okumaktır.

Dosya tanımlayıcı kimliği, open () veya pipe () sistem çağrısı çağrıldıktan sonra döndürülen ilgili dosyayı tanımlamak içindir. Dosyadan okunmadan önce dosyanın açılması gerekir. Pipe () sistem çağrısının çağrılması durumunda otomatik olarak açılır.

Bu çağrı, başarı durumunda okunan bayt sayısını (veya dosyanın sonuyla karşılaşma durumunda sıfır) ve başarısızlık durumunda -1'i döndürür. Verinin mevcut olmaması veya dosyanın kapatılması durumunda, dönüş baytları istenen bayt sayısından daha küçük olabilir. Arıza durumunda uygun hata numarası belirlenir.

Başarısızlığın nedenini öğrenmek için, errno değişkeni veya perror () işlevi ile kontrol edin.

#include<unistd.h>

ssize_t write(int fd, void *buf, size_t count)

Yukarıdaki sistem çağrısı, fd dosya tanımlayıcısının argümanları, ayrılmış belleğe sahip uygun bir arabellek (statik ya da dinamik) ve arabellek boyutu ile belirtilen dosyaya yazmaktır.

Dosya tanımlayıcı kimliği, open () veya pipe () sistem çağrısı çağrıldıktan sonra döndürülen ilgili dosyayı tanımlamak içindir.

Dosyaya yazılmadan önce dosyanın açılması gerekiyor. Pipe () sistem çağrısının çağrılması durumunda otomatik olarak açılır.

Bu çağrı, başarı durumunda yazılan bayt sayısını (veya hiçbir şey yazılmaması durumunda sıfır) ve başarısızlık durumunda -1'i döndürür. Arıza durumunda uygun hata numarası belirlenir.

Başarısızlığın nedenini öğrenmek için, errno değişkeni veya perror () işlevi ile kontrol edin.

Örnek Programlar

Aşağıda bazı örnek programlar verilmiştir.

Example program 1 - Boru kullanarak iki mesaj yazmak ve okumak için program.

Algoritma

Step 1 - Bir boru oluşturun.

Step 2 - Boruya bir mesaj gönderin.

Step 3 - İletiyi borudan alın ve standart çıktıya yazın.

Step 4 - Boruya başka bir mesaj gönderin.

Step 5 - İletiyi borudan alın ve standart çıktıya yazın.

Note - Mesajların alınması, tüm mesajlar gönderildikten sonra da yapılabilir.

Source Code: simplepipe.c

#include<stdio.h>
#include<unistd.h>

int main() {
   int pipefds[2];
   int returnstatus;
   char writemessages[2][20]={"Hi", "Hello"};
   char readmessage[20];
   returnstatus = pipe(pipefds);
   
   if (returnstatus == -1) {
      printf("Unable to create pipe\n");
      return 1;
   }
   
   printf("Writing to pipe - Message 1 is %s\n", writemessages[0]);
   write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
   read(pipefds[0], readmessage, sizeof(readmessage));
   printf("Reading from pipe – Message 1 is %s\n", readmessage);
   printf("Writing to pipe - Message 2 is %s\n", writemessages[0]);
   write(pipefds[1], writemessages[1], sizeof(writemessages[0]));
   read(pipefds[0], readmessage, sizeof(readmessage));
   printf("Reading from pipe – Message 2 is %s\n", readmessage);
   return 0;
}

Note- İdeal olarak, geri dönüş durumunun her sistem çağrısı için kontrol edilmesi gerekir. Süreci basitleştirmek için, tüm aramalar için kontroller yapılmaz.

Yürütme Adımları

Derleme

gcc -o simplepipe simplepipe.c

Yürütme / Çıktı

Writing to pipe - Message 1 is Hi
Reading from pipe – Message 1 is Hi
Writing to pipe - Message 2 is Hi
Reading from pipe – Message 2 is Hell

Example program 2 - Üst ve alt süreçleri kullanarak kanal aracılığıyla iki mesaj yazmak ve okumak için program.

Algoritma

Step 1 - Bir boru oluşturun.

Step 2 - Bir çocuk süreci oluşturun.

Step 3 - Ana süreç boruya yazar.

Step 4 - Alt süreç, mesajı borudan alır ve standart çıktıya yazar.

Step 5 - 3. ve 4. adımları tekrarlayın.

Source Code: pipewithprocesses.c

#include<stdio.h>
#include<unistd.h>

int main() {
   int pipefds[2];
   int returnstatus;
   int pid;
   char writemessages[2][20]={"Hi", "Hello"};
   char readmessage[20];
   returnstatus = pipe(pipefds);
   if (returnstatus == -1) {
      printf("Unable to create pipe\n");
      return 1;
   }
   pid = fork();
   
   // Child process
   if (pid == 0) {
      read(pipefds[0], readmessage, sizeof(readmessage));
      printf("Child Process - Reading from pipe – Message 1 is %s\n", readmessage);
      read(pipefds[0], readmessage, sizeof(readmessage));
      printf("Child Process - Reading from pipe – Message 2 is %s\n", readmessage);
   } else { //Parent process
      printf("Parent Process - Writing to pipe - Message 1 is %s\n", writemessages[0]);
      write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
      printf("Parent Process - Writing to pipe - Message 2 is %s\n", writemessages[1]);
      write(pipefds[1], writemessages[1], sizeof(writemessages[1]));
   }
   return 0;
}

Yürütme Adımları

Compilation

gcc pipewithprocesses.c –o pipewithprocesses

Execution

Parent Process - Writing to pipe - Message 1 is Hi
Parent Process - Writing to pipe - Message 2 is Hello
Child Process - Reading from pipe – Message 1 is Hi
Child Process - Reading from pipe – Message 2 is Hello

Boruları Kullanarak İki Yönlü İletişim

Boru iletişimi tek yönlü iletişim olarak görülür, yani ya ana süreç yazar ve alt süreç okur ya da tam tersi, ancak her ikisi birden değil. Bununla birlikte, hem ebeveynin hem de çocuğun borulardan aynı anda yazması ve okuması gerekiyorsa, çözüm, boruları kullanan iki yönlü bir iletişimdir. İki yönlü iletişim kurmak için iki boru gereklidir.

İki yönlü iletişime ulaşmanın adımları aşağıdadır -

Step 1- İki boru oluşturun. Birincisi, ebeveynin yazması ve çocuğun okuması için, diyelim ki boru1. İkincisi, çocuğun yazması ve ebeveynin okuması için, diyelim ki boru2.

Step 2 - Bir çocuk süreci oluşturun.

Step 3 - Her iletişim için yalnızca bir uca ihtiyaç duyulduğundan istenmeyen uçları kapatın.

Step 4 - Ana süreçteki istenmeyen uçları kapatın, boru1'in sonunu okuyun ve boru2'nin sonunu yazın.

Step 5 - Alt süreçte istenmeyen uçları kapatın, boru1'in sonunu yazın ve boru2'nin sonunu okuyun.

Step 6 - İletişimi gerektiği gibi gerçekleştirin.

Örnek Programlar

Sample program 1 - Boruları kullanarak iki yönlü iletişim sağlamak.

Algoritma

Step 1 - Üst sürecin yazması ve alt sürecin okuması için boru1 oluşturun.

Step 2 - Alt sürecin yazması ve ana sürecin okuması için boru2 oluşturun.

Step 3 - Üst ve alt taraftan borunun istenmeyen uçlarını kapatın.

Step 4 - Bir mesaj yazmak için ebeveyn süreci ve ekranda okumak ve görüntülemek için alt süreç.

Step 5 - Bir mesaj yazmak için çocuk süreç ve ekranda okumak ve görüntülemek için ana süreç.

Source Code: twowayspipe.c

#include<stdio.h>
#include<unistd.h>

int main() {
   int pipefds1[2], pipefds2[2];
   int returnstatus1, returnstatus2;
   int pid;
   char pipe1writemessage[20] = "Hi";
   char pipe2writemessage[20] = "Hello";
   char readmessage[20];
   returnstatus1 = pipe(pipefds1);
   
   if (returnstatus1 == -1) {
      printf("Unable to create pipe 1 \n");
      return 1;
   }
   returnstatus2 = pipe(pipefds2);
   
   if (returnstatus2 == -1) {
      printf("Unable to create pipe 2 \n");
      return 1;
   }
   pid = fork();
   
   if (pid != 0) // Parent process {
      close(pipefds1[0]); // Close the unwanted pipe1 read side
      close(pipefds2[1]); // Close the unwanted pipe2 write side
      printf("In Parent: Writing to pipe 1 – Message is %s\n", pipe1writemessage);
      write(pipefds1[1], pipe1writemessage, sizeof(pipe1writemessage));
      read(pipefds2[0], readmessage, sizeof(readmessage));
      printf("In Parent: Reading from pipe 2 – Message is %s\n", readmessage);
   } else { //child process
      close(pipefds1[1]); // Close the unwanted pipe1 write side
      close(pipefds2[0]); // Close the unwanted pipe2 read side
      read(pipefds1[0], readmessage, sizeof(readmessage));
      printf("In Child: Reading from pipe 1 – Message is %s\n", readmessage);
      printf("In Child: Writing to pipe 2 – Message is %s\n", pipe2writemessage);
      write(pipefds2[1], pipe2writemessage, sizeof(pipe2writemessage));
   }
   return 0;
}

Yürütme Adımları

Derleme

gcc twowayspipe.c –o twowayspipe

Yürütme

In Parent: Writing to pipe 1 – Message is Hi
In Child: Reading from pipe 1 – Message is Hi
In Child: Writing to pipe 2 – Message is Hello
In Parent: Reading from pipe 2 – Message is Hello