Zastanawialiście się może, jak wygląda komunikacja między aplikacjami? Procesy istniejące w systemie mogą przecież, pomimo twardych reguł zarządzania, komunikować się ze sobą.

IPC, Inter process communication, pipe, fifo, filo

 

W Linuxie mamy do dyspozycji kilka metod komunikacji, bazujących na różnych tzw. przestrzeniach. Komunikacja niskopoziomowa odbywa się przy udziale jądra, wysokopoziomowa to np. istniejący prawie w każdej dystrybucji DBUS. Choć DBUS i inne systemy komunikacji wysokiego poziomu zdają się być dostatecznie dobrym rozwiązaniem dla wszystkich aplikacji – tak nie jest. Często, gdy tworzymy aplikacje pracujące jako demony z uprawnieniami super użytkownika (root) staramy się, aby komunikacja między nimi odbywała się na zasadach innych, niż pozostałych, należących do użytkownika procesów. W takiej sytuacji przychodzi nam właśnie IPC – komunikacja międzyprocesowa – której implementacja została umieszczona w jądrze systemu i bezpośrednio przez nie jest zarządzana.

Dziś przedstawię Wam – za sprawą ograniczenia czasowego i ogromu informacji – dwa rodzaje łączy, stanowiących zaledwie część IPC – łącza nazwane oraz łącza nienazwane.

 

Łącza nienazwane – Linux PIPE

Jest to rodzaj komunikacji w których oba procesy korzystają z tzw. PIPE (potoku) do wymiany danych pomiędzy potomkami. Przykład działającej implementacji w języku C, to:

 

Zapis do PIPE (potomek)

Potomek zapisuje wiadomość złożoną z N-bajtów podobnie jak robi się to ze zwykłymi plikami. Wykorzystywany jest jednak deskryptor łącza zamiast deskryptora pliku.

Wcześniej jednak potomek zamyka koniec „rury” służący do odczytu przekazując mu deskryptor do odczytu.

void pipe_zapis() {
char wiadomosc[] = „Wiadomosc do wyslania przez Pipe”;
close(pipe_id_lacza[ID_ODCZYTU]);
write(pipe_id_lacza[ID_ZAPISU], wiadomosc, (strlen(wiadomosc)+1));
exit(0);
}

Odczyt z PIPE (rodzic)

Rodzic tworzy bufor do odczytu, do którego wczytuje N-bajtów z PIPE, podobnie jak robi się to ze zwykłymi plikami. Wcześniej jednak rodzic zamyka koniec „rury” służący do zapisu.

void pipe_odczyt() {
char bufor_odczytu[80];
close(pipe_id_lacza[ID_ZAPISU]);
int rozmiar_odczytu = read(pipe_id_lacza[ID_ODCZYTU], bufor_odczytu, sizeof(bufor_odczytu));
printf(„Odebrana wiadomosc od procesu potomnego: %s”, bufor_odczytu);
}

 

Efekt powyższego kodu:

Odebrana wiadomosc od procesu potomnego: Wiadomosc do wyslania przez Pipe

Kod programu obrazującego PIPE oraz tworzenie procesów z wykorzystaniem polecenia systemowego FORK znajdziecie do pobrania tutaj (evmipl_mateuszm_przyklad_pipe.c).

 

Łącze nazwane – kolejka FIFO

Jest to rodzaj komunikacji oparty o stworzenie potoku, który istnieje w systemie jako specjalny plik. Łącza te bazują na zasadzie kolejkowania komunikatów za pomocą mechanizmu, jakim jest kolejka FIFO (pierwszy wchodzi, pierwszy wychodzi). Jest to idealne rozwiązanie komunikacyjne w sytuacji, gdy procesy nie są ze sobą powiązane (nie pochodzą od jednego rodzica – w uproszczeniu „aplikacji”).

 

Tworzenie i zapisywanie do kolejki FIFO (writer):

Na początku tworzymy plik łącza nazwanego – kolejka FIFO – poleceniem mkfifo i nadajemy mu stosowne uprawnienia systemowe – odczyt/zapis dla użytkownika będącego właścicielem procesu – 0600 czyli odpowiednik „-rw——-„. Wybranym katalogiem jest katalog /tmp i to tam zostanie stworzony plik o nazwie „fifo”.

int zapis_do_fifo()
{
int ipc_fifo_fd;

mkfifo(„/tmp/fifo”, 0600);

char wiadomosc[] = „To jest wiadomosc do FIFO z evmipl_mateuszm_ipc_fifowriter.c”;

ipc_fifo_fd = open(„/tmp/fifo”, O_WRONLY);

while (1) {
write(ipc_fifo_fd, wiadomosc, (strlen(wiadomosc)+1));
usleep(30);
}
return 0;
}

 

Odczytywanie z kolejki FIFO (reader):

Odczyt łącza nazwanego odbywa się w identyczny sposób jak dowolnego innego pliku z wykorzystaniem – logicznie – „open()”, „read()” oraz „close()”.

int odczyt_z_fifo()
{
int ipc_fifo_fd;
ipc_fifo_fd = open(„/tmp/fifo”, O_RDONLY);
char bufor_odczytu[80];
read(ipc_fifo_fd, bufor_odczytu, sizeof(bufor_odczytu));
close(ipc_fifo_fd);
printf(„Wiadomosc z FIFO: %s”, bufor_odczytu);
return 0;
}

 

Pliki readera i writera możecie pobrać tutaj i skompilować na własnej maszynie. Ponieważ jest to tylko przykład, nie zapomnijcie usunąć pliku /tmp/fifo po zakończeniu zabawy. Najpierw musicie uruchomić writer a następnie reader.

Źródło writera: evmipl_mateuszm_przyklad_fifo_writer.c
Źródło readera: evmipl_mateuszm_przyklad_fifo_reader.c

 

C.D.N

 

Pozdrawiam, M.M.