Provided by: manpages-pl_0.7-2_all bug

NAZWA

       unix - gniazda lokalnej komunikacji międzyprocesowej

SKŁADNIA

       #include <sys/socket.h>
       #include <sys/un.h>

       unix_socket = socket(AF_UNIX, type, 0);
       error = socketpair(AF_UNIX, type, 0, int *sv);

OPIS

       Rodzina  gniazd AF_UNIX (znana również jako AF_LOCAL) służy do wydajnej komunikacji pomiędzy procesami na
       tej samej maszynie. Zgodnie z tradycją, gniazda domeny uniksowej mogą być albo anonimowe (tworzone  przez
       socketpair(2)),  albo  skojarzone  z  plikiem typu gniazda. Linux wspiera również abstrakcyjną przestrzeń
       nazw, niezależną od systemu plików.

       Poprawne typy gniazd w domenie Uniksa to: SOCK_STREAM dla gniazd strumieniowych, SOCK_DGRAM  dla   gniazd
       datagramowych,  które  zachowują granice komunikatów (w przypadku większości implementacji Uniksa gniazda
       uniksowe są zawsze niezawodne i nie zmieniają kolejności datagramów),  oraz  (od  wersji  Linuksa  2.6.4)
       SOCK_SEQPACKET  dla  gniazd  pakietów  sekwencyjnych zorientowanych połączeniowo, które zachowują granice
       komunikatu i dostarczają komunikaty w kolejności ich wysyłania.

       Za pośrednictwem pomocniczych danych można przez gniazda domeny uniksowej przekazywać do innych  procesów
       deskryptory plików i uwierzytelnienia procesów.

   Format adresu
       Adres gniazda domeny uniksowej jest reprezentowany przez następującą strukturę:

           struct sockaddr_un {
               sa_family_t sun_family;               /* AF_UNIX */
               char        sun_path[108];            /* ścieżka dostępu */
           };

       Pole  sun_family  zawsze  zawiera  AF_UNIX.  W  Linuksie  sun_path  ma rozmiar 108 bajtów, zob. też UWAGI
       poniżej.

       Różne wywołania systemowe (np. bind(2), connect(2)  i  sendto(2))  przyjmują  argument  sockaddr_un  jako
       wejście.  Niektóre inne wywołania systemowe (np. getsockname(2), getpeername(2), recvfrom(2) i accept(2))
       zwracają argument tego typu.

       W strukturze sockaddr_un rozróżniane są trzy typy adresów:

       *  pathname: gniazdo domeny uniksowej może zostać  związane  z  zakończoną  znakiem  NULL  nazwą  ścieżki
          systemowej  za  pomocą  bind(2).  Jeśli  adres  ścieżki  gniazda  jest  zwracany  (przez  jedno  z ww.
          wywołań systemowych) to jego długością jest

              offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1

          a sun_path zawiera zakończoną null ścieżkę. (W Linuksie powyższe wyrażenie offsetof() jest  równe  tej
          samej  wartości  co  sizeof(sa_family_t),  lecz  niektóre inne implementacje dołączają inne pola przed
          sun_path, więc bardziej przenośnie, wyrażenie offsetof() opisuje rozmiar struktury adresu).

          Więcej informacji o ścieżkach gniazd znajduje się poniżej.

       *  unnamed: Gniazdo strumieniowe nie związane z  nazwą  ścieżki  za  pomocą  bind(2)  nie  jest  nazwane.
          Podobnie  dwa  gniazda  utworzone przez socketpair(2) nie są nazwane. Jeśli adres nienazwanego gniazda
          jest zwracany, to jego długością jest  sizeof(sa_family_t),  a  zawartość  sun_path  nie  powinna  być
          sprawdzana.

       *  abstract:  adres  gniazda  abstrakcyjnego  jest rozróżniany (od adresu ścieżki) po tym, że sun_path[0]
          jest bajtem NULL ("\0"). Adres gniazda znajduje się w przestrzeni nazw podanej w dodatkowych bajtach w
          sun_path,  które  są  pokryte  przez  długość  struktury  adresu (Bajty NULL w nazwie nie mają żadnego
          specjalnego znaczenia). Nazwa nie ma żadnego powiązania z nazwą  pliku  w  systemie  plików.  Zwracany
          adres  gniazda abstrakcyjnego ma w polu addrlen ustawioną długość większą niż sizeof(sa_family_t) (tj.
          większą niż 2), a nazwa gniazda zawarta jest w pierwszych (addrlen - sizeof(sa_family_t)) bajtach pola
          sun_path. Przestrzeń nazw gniazd abstrakcyjnych jest  nieprzenaszalnym rozszerzeniem Linuksa.

   Ścieżki gniazd
       Przy   przypisywaniu  gniazda  do  ścieżki  powinno  się przestrzegać  kilku  zasad  w  celu  maksymalnej
       przenośności i łatwości programowania:

       *  Ścieżka w sun_path powinna być zakończona znakiem NULL.

       *  Długość ścieżki, w tym kończący bajt null nie powinna przekraczać rozmiaru sun_path.

       *  Argument addrlen opisujący obejmującą strukturę sockaddr_un powinien mieć wartość przynajmniej:

              offsetof(struct sockaddr_un, sun_path)+strlen(addr.sun_path)+1

          lub, prościej, addrlen powinien być podany jako sizeof(struct sockaddr_un).

       W różnych implementacjach różnie obsługiwane są adresy  gniazd  domen  Uniksa,  które  nie  przestrzegają
       powyższych  zaleceń.  Na  przykład niektóre (lecz nie wszystkie) implementacje dodają kończący znak null,
       jeśli nie jest on obecny w przekazanej sun_path.

       Przy programowaniu przenośnych aplikacji proszę wziąć pod uwagę, że niektóre implementację mają  sun_path
       o długości zaledwie 92 bajtów.

       Różne  wywołania  systemowe  (accept(2),  recvfrom(2), getsockname(2), getpeername(2)) zwracają struktury
       adresów gniazd. Gdy chodzi o gniazda domeny Uniksa, wartość-rezultat argumentu  addrlen  umieszczonego  w
       wywołaniu  powinna  być zainicjowana  jw. Gdy jest zwracany, argument ten jest ustawiany aby przedstawiać
       aktualny rozmiar struktury adresu. Wywołujący powinien sprawdzić wartość zwracaną w tym argumencie, jeśli
       wartość  wyjściowa przekracza wartość wejściową, to nie ma gwarancji, że kończący znak null jest obecny w
       sun_path (zob PROBLEMY).

   Opcje gniazda
       Ze względów historycznych następujące opcje gniazd są podawane przy typie SOL_SOCKET, pomimo  że  są  one
       specyficzne  dla  AF_UNIX.  Można je ustawić za pomocą setsockopt(2), a odczytać za pomocą getsockopt(2),
       podając SOL_SOCKET jako rodzinę gniazd.

       SO_PASSCRED
              Włącza otrzymywanie uwierzytelnień od procesu wysyłającego komunikat  pomocniczy.  Przy  włączonej
              tej  opcji  i niepołączonym jeszcze gnieździe, unikatowa nazwa gniazda z abstrakcyjnej przestrzeni
              nazw jest generowana automatycznie. Oczekiwany jest logiczny znacznik typu całkowitego.

   Automatyczne przypisywanie adresów
       Jeśli w wywołaniu bind(2) podane zostanie addrlen równe sizeof(sa_family_t) lub opcja SO_PASSCRED gniazda
       była  ustawiona  dla  gniazda nieprzypisanego do adresu, wtedy gniazdo jest automatycznie przypisywane do
       adresu abstrakcyjnego. Adres ten składa się z bajtu NULL, po którym następuje 5 bajtów ze  zbioru  znaków
       [0-9a-f].  W  związku  z  tym liczba automatycznie przypisywanych adresów jest ograniczona przez 2^20. (W
       Linuksie 2.1.15, w którym dodano możliwość automatycznego przypisywania adresów, i w  kolejnych  wersjach
       używane było 8 bajtów, a limit wynosił 2^32 adresów. Zostało to zmienione na 5 bajtów w Linuksie 2.3.15).

   API gniazd
       W  kolejnych  paragrafach  opisano  pewne  szczegóły implementacji API gniazd domeny UNIX specyficzne dla
       Linuksa oraz cechy niewspierane.

       Gniazda z domeny uniksowej nie obsługują zawiadomienia o danych  autonomicznych  (flaga  MSG_OOB  funkcji
       send(2) i recv(2)).

       Flaga MSG_MORE funkcji send(2) nie jest obsługiwana dla gniazd domeny uniksowej.

       Użycie MSG_TRUNC w argumencie flags funkcji recv(2) nie jest obsługiwane dla gniazd domeny uniksowej.

       Opcja  SO_SNDBUF  działa  w  przypadku  gniazd  domeny uniksowej, ale opcja SO_RCVBUF już nie. Dla gniazd
       datagramowych wartość SO_SNDBUF nakłada górny limit na rozmiar wychodzących datagramów.  Limit  ten  jest
       liczony  jako  podwojona (patrz socket(7)) wartość opcji minus 32 bajty wymagane na informacje nie będące
       danymi.

   Komunikaty pomocnicze
       Dane pomocnicze są wysyłane i odbierane za pomocą sendmsg(2)  i  recvmsg(2).  Ze  względów  historycznych
       komunikaty  pomocnicze  poniższych  typów są podawane przy typie SOL_SOCKET, pomimo że są one specyficzne
       dla AF_UNIX. Aby je wysłać, należy ustawić pole  cmsg_level  struktury  cmsghdr  na  SOL_SOCKET,  a  pole
       cmsg_type na typ. Więcej informacji można znaleźć w cmsg(3).

       SCM_RIGHTS
              Odbieranie  od  innego procesu lub wysyłanie do niego zbioru otwartych deskryptorów plików. Porcja
              danych zawiera tablicę liczb całkowitych będących  deskryptorami  plików.  Przekazane  deskryptory
              plików zachowują się tak, jakby zostały utworzone za pomocą dup(2).

       SCM_CREDENTIALS
              Odbieranie  lub  wysyłanie uwierzytelnień uniksowych. Może służyć do autoryzacji. Uwierzytelnienia
              są przekazywane jako komunikat pomocniczy  typu  struct  ucred,  zdefiniowanego  w  <sys/socket.h>
              następująco:

                  struct ucred {
                      pid_t pid;  /* identyfikator procesu wysyłającego */
                      uid_t uid;  /* ident. użytkownika procesu wysyłającego */
                      gid_t gid;  /* ident. grupy procesu wysyłającego */
                  };

              Począwszy  od  wersji  2.8  biblioteki glibc, aby uzyskać dostęp do definicji powyższej struktury,
              należy zdefiniować makro _GNU_SOURCE (przed dołączeniem jakichkolwiek plików nagłówkowych).

              Jądro sprawdza uwierzytelnienia podane przez wysyłającego.  Proces  o  efektywnym  ID  użytkownika
              równym  0  może  podać  wartości,  które  różnią  się  od jego własnych. W pozostałych przepadkach
              wysyłający musi podać swój własny identyfikator  procesu  (o  ile  nie  ma  ustawionego  znacznika
              CAP_SYS_ADMIN),  swój  własny  identyfikator  użytkownika, efektywny identyfikator użytkownika lub
              ustawiony identyfikator użytkownika (o ile nie ma  ustawionego  znacznika  CAP_SETUID)  oraz  swój
              własny identyfikator grupy, efektywny identyfikator grupy lub ustawiony identyfikator grupy (o ile
              nie ma ustawionego znacznika CAP_SETGID). Aby otrzymać komunikat typu struct  ucred,  dla  gniazda
              musi być włączona opcja SO_PASSCRED.

   Kontrolki systemowe (ioctl)
       Następujące wywołania ioctl(2) zwracają informacje w parametrze value. Poprawna składnia to:

              int value;
              error = ioctl(unix_socket, ioctl_type, &value);

       ioctl_type może przyjmować wartość:

       SIOCINQ
              Dla  gniazda  SOCK_STREAM  funkcja zwraca ilość nieprzeczytanych jeszcze danych znajdujących się w
              kolejce buforu odbierającego. Gniazdo nie może się  znajdować  w  stanie  "LISTEN";  w  przeciwnym
              wypadku   zostanie   zwrócony  błąd  (EINVAL).  SIOCINQ  jest  zdefiniowany  w  <linux/sockios.h>.
              Alternatywnie można użyć synonimu FIONREAD zdefiniowanego w <sys/ioctl.h>. Dla gniazda SOCK_DGRAM,
              zwracana  wartość  jest  taka  sama  jak  w  przypadku datagramowego gniazda domeny Internet; zob.
              udp(7).

BŁĘDY

       EADDRINUSE
              Podany adres lokalny jest zajęty lub obiekt gniazda w systemie plików już istnieje.

       ECONNREFUSED
              Adres zdalny podany w connect(2) nie odnosił  się  do  gniazda  nasłuchującego.  Błąd  może  także
              wystąpić jeśli docelowa ścieżka nie jest gniazdem.

       ECONNRESET
              Zdalne gniazdo zostało nieoczekiwanie zamknięte.

       EFAULT Nieprawidłowy adres pamięci użytkownika.

       EINVAL Podano nieprawidłowy argument. Najczęstszą przyczyną jest brak ustawionego AF_UNIX w polu sun_type
              przekazywanych gniazdu adresów lub nieprawidłowy dla danej operacji stan gniazda.

       EISCONN
              Wywołano connect(2) dla już połączonego gniazda lub podano adres docelowy dla połączonego gniazda.

       ENOENT Nie istnieje ścieżka dla zdalnego adresu przekazanego do connect(2).

       ENOMEM Brak pamięci.

       ENOTCONN
              Operacja na gnieździe wymaga adresu docelowego, a gniazdo nie jest połączone.

       EOPNOTSUPP
              Operacja strumieniowa wywołana  dla  gniazda  niestrumieniowego  lub  próba  użycia  opcji  danych
              autonomicznych.

       EPERM  Wysyłający podał nieprawidłowe uwierzytelnienia w struct ucred.

       EPIPE  Zdalne  gniazdo  strumieniowe  zostało  zamknięte. Gdy włączone, wysyłany jest jednocześnie sygnał
              SIGPIPE. Można tego uniknąć, przekazując znacznik MSG_NOSIGNAL do sendmsg(2) lub recvmsg(2).

       EPROTONOSUPPORT
              Podanym protokołem nie jest AF_UNIX.

       EPROTOTYPE
              Typ gniazda zdalnego różni się od typu gniazda lokalnego (SOCK_DGRAM wobec SOCK_STREAM)

       ESOCKTNOSUPPORT
              Nieznany typ gniazda.

       Inne błędy mogą zostać wygenerowane przez podstawową warstwę  gniazd  lub  przez  system  plików  podczas
       tworzenia  obiektu  gniazda  w  systemie plików. Więcej informacji można znaleźć na odpowiednich stronach
       podręcznika.

WERSJE

       SCM_CREDENTIALS oraz abstrakcyjna przestrzeń nazw zostały wprowadzone w Linuksie 2.2  i  nie  należy  ich
       używać  w  przenośnych  programach. (Niektóre systemy wywodzące się z BSD również wspierają przekazywanie
       uwierzytelnień, ale implementacje różnią się szczegółami).

UWAGI

       W linuksowej implementacji dla gniazda widocznych w systemie plików są stosowane uprawnienia katalogu,  w
       którym  się  znajdują.  Ich  właściciela,  grupę  oraz  prawa  dostępu  można zmieniać. Gdy proces nie ma
       uprawnień do zapisu i przeszukiwania (uruchamiania) do katalogu, w którym  tworzone  jest  gniazdo,  jego
       utworzenie  się nie powiedzie. Połączenie z obiektem gniazda wymaga praw odczytu/zapisu. Takie zachowanie
       różni się od zachowania wielu systemów wywodzących się z  BSD,  które  ignorują  uprawnienia  dla  gniazd
       uniksowych. Programy przenośne ze względów bezpieczeństwa nie powinny polegać na tej cesze.

       W  trakcie łączenia się z gniazdem mającym przypisaną nazwę pliku, tworzony jest plik specjalny gniazda w
       systemie plików, który musi zostać usunięty (za pomocą unlink(2)) przez wywołującego, gdy już nie  będzie
       potrzebny.  Stosuje  się  tu zwykła uniksowa składnia opóźnionego zamknięcia (ang. close-behind): gniazdo
       można skasować w dowolnym momencie, ale zostanie ono ostatecznie usunięte z systemu plików po  zamknięciu
       ostatniego odwołania do niego.

       Aby  przekazać  deskryptory  plików  lub  uwierzytelnienia  poprzez  SOCK_STREAM trzeba wysłać/odebrać co
       najmniej jeden bajt niepomocniczych danych w tym samym wywołaniu sendmsg(2) lub recvmsg(2)

       Gniazda strumieniowe z domeny uniksowej nie obsługują zawiadomienia o danych autonomicznych.

PROBLEMY

       Przy wiązaniu gniazda z adresem, Linux jest jedną z implementacji dodających  kończące  null,  jeśli  nie
       poda  się  go  w  sun_path.  Zwykle jest to bezproblemowe, gdy adres gniazda jest pozyskiwany będzie on o
       jeden bajt dłuższy niż  podawany  początkowo.  Jest  jednak  jeden  przypadek  mogący  spowodować  mylące
       zachowanie:  jeśli podany zostanie adres 108 bajtowy, bez znaku null, to dodanie znaku null spowodowałoby
       przekroczenie długości ścieżki poza sizeof(sun_path). W konsekwencji, przy  pozyskiwaniu  adresu  gniazda
       (np.  poprzez  accept(2)),  jeśli wejściowy argument addrlen dla pozyskiwanego wywołania jest podany jako
       sizeof(struct sockaddr_un), to zwrócona struktura adresu nie będzie miała kończącego null w sun_path.

       Dodatkowo, niektóre implementacje nie wymagają kończącego null przy wiązaniu  gniazda  (argument  addrlen
       jest  używany  do  określenia  długości  sun_path),  a  gdy w tych implementacjach jest pozyskiwany adres
       gniazda, to nie ma kończącego null w sun_path.

       Aplikacje pozyskujące adresy gniazd mogą posiadać (przenośny) kod do obsługi możliwości,  że  w  sun_path
       nie ma kończącego null zauważając fakt, że liczba prawidłowych bajtów w ścieżce to:

           strnlen(addr.sun_path, addrlen - offsetof(sockaddr_un, sun_path))

       Alternatywnie, aplikacja może pozyskać adres gniazda przez przydzielenie buforu o rozmiarze sizeof(struct
       sockaddr_un)+1 który jest wyzerowany przed pozyskaniem. Pobierające wywołanie może określić addrlen  jako
       sizeof(struct  sockaddr_un),  a  dodatkowy  bajt zero zapewnia, że w łańcuchu zwróconym w sun_path będzie
       kończące null:

          void *addrp;

          addrlen = sizeof(struct sockaddr_un);
          addrp = malloc(addrlen + 1);
          if (addrp == NULL)
              /* Obsługa błędu */ ;
          memset(addrp, 0, addrlen + 1);

          if (getsockname(sfd, (struct sockaddr *) addrp, &addrlen)) == -1)
              /* obsługa błędu */ ;

          printf("sun_path = %s\n", ((struct sockaddr_un *) addrp)->sun_path);

       Tego bałaganu można uniknąć, jeśli jest pewność, że aplikacja tworząca ścieżki gniazd  przestrzega  reguł
       opisanych powyżej rozdziale Ścieżki gniazd.

PRZYKŁAD

       Poniższy  kod  demonstruje użycie gniazd pakietów sekwencyjnych do lokalnej komunikacji międzyprocesowej.
       Składa się z dwóch programów. Serwer czeka na połączenie z programu klienckiego. Klient wysyła  każdy  ze
       swoich  argumentów  wiersza  poleceń w oddzielnych wiadomościach. Serwer traktuje przychodzące wiadomości
       jako liczby całkowite i dodaje je.  Klient  wysyła  łańcuch  polecenia  "END".  Serwer  odsyła  komunikat
       zawierający  sumę  klienckich  liczb  całkowitych.  Klient  wypisuje  sumę  i  wychodzi.  Serwer czeka na
       połączenie od kolejnego klienta. Aby  zatrzymać serwer,  klient  jest  wywoływany  z  argumentem  wiersza
       poleceń "DOWN".

       Podczas  działania  serwera  w  tle  i  kolejnych  uruchomień klienta zarejestrowano następujące wyjście.
       Wykonywanie programu serwera kończy się, gdy otrzymuje on polecenie "DOWN".

   Przykładowe wyjście
           $ ./server &
           [1] 25887
           $ ./client 3 4
           Result = 7
           $ ./client 11 -5
           Result = 6
           $ ./client DOWN
           Result = 0
           [1]+  Done                    ./server
           $

   Kod źródłowy programu
       /*
        * Plik connection.h
        */

       #define SOCKET_NAME "/tmp/9Lq7BNBnBycd6nxy.socket"
       #define BUFFER_SIZE 12

       /*
        * Plik server.c
        */

       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/un.h>
       #include <unistd.h>
       #include "connection.h"

       int
       main(int argc, char *argv[])
       {
           struct sockaddr_un name;
           int down_flag = 0;
           int ret;
           int connection_socket;
           int data_socket;
           int result;
           char buffer[BUFFER_SIZE];

           /*
            * Jeśli program wyszedł niejawnie w ostatnim przebiegu,
            * usuwa gniazdo.
            */

           unlink(SOCKET_NAME);

           /* Tworzenie lokalnego gniazda. */

           connection_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
           if (connection_socket == -1) {
               perror("socket");
               exit(EXIT_FAILURE);
           }

           /*
            * Dla przenośności wyczyść całą strukturę, ponieważ niektóre
            * implementacje mają dodatkowe (niestandardowe) pola
            * w strukturze.
            */

           memset(&name, 0, sizeof(struct sockaddr_un));

           /* Wiązanie gniazda z nazwą gniazda. */

           name.sun_family = AF_UNIX;
           strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);

           ret = bind(connection_socket, (const struct sockaddr *) &name,
                      sizeof(struct sockaddr_un));
           if (ret == -1) {
               perror("bind");
               exit(EXIT_FAILURE);
           }

           /*
            * Przygotowywanie do akceptowania połączeń. Rozmiar bufora jest
            * ustawiany na 20. Podczas przetwarzania jednego żądania, inne
            * mogą czekać.
            */

           ret = listen(connection_socket, 20);
           if (ret == -1) {
               perror("listen");
               exit(EXIT_FAILURE);
           }

           /* To główna pętla do obsługi połączeń. */

           for (;;) {

               /* Czekanie na połączenie przychodzące. */

               data_socket = accept(connection_socket, NULL, NULL);
               if (ret == -1) {
                   perror("accept");
                   exit(EXIT_FAILURE);
               }

               result = 0;
               for(;;) {

                   /* Czekanie na następny pakiet danych. */

                   ret = read(data_socket, buffer, BUFFER_SIZE);
                   if (ret == -1) {
                       perror("read");
                       exit(EXIT_FAILURE);
                   }

                   /* Upewnienie się, że bufor kończy się 0. */

                   buffer[BUFFER_SIZE - 1] = 0;

                   /* Obsługa poleceń. */

                   if (!strncmp(buffer, "DOWN", BUFFER_SIZE)) {
                       down_flag = 1;
                       break;
                   }

                   if (!strncmp(buffer, "END", BUFFER_SIZE)) {
                       break;
                   }

                   /* Dodawanie otrzymanej sumy. */

                   result += atoi(buffer);
               }

               /* Wysyłanie wyniku. */

               sprintf(buffer, "%d", result);
               ret = write(data_socket, buffer, BUFFER_SIZE);

               if (ret == -1) {
                   perror("write");
                   exit(EXIT_FAILURE);
               }

               /* Zamknięcie gniazda. */

               close(data_socket);

               /* Wyjście po poleceniu DOWN. */

               if (down_flag) {
                   break;
               }
           }

           close(connection_socket);

           /* Usunięcie gniazda. */

           unlink(SOCKET_NAME);

           exit(EXIT_SUCCESS);
       }

       /*
        * Plik client.c
        */

       #include <errno.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <sys/socket.h>
       #include <sys/un.h>
       #include <unistd.h>
       #include "connection.h"

       int
       main(int argc, char *argv[])
       {
           struct sockaddr_un addr;
           int i;
           int ret;
           int data_socket;
           char buffer[BUFFER_SIZE];

           /* Tworzenie lokalnego gniazda. */

           data_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
           if (data_socket == -1) {
               perror("socket");
               exit(EXIT_FAILURE);
           }

           /*
            * Dla przenośności wyczyść całą strukturę, ponieważ niektóre
            * implementacje mają dodatkowe (niestandardowe) pola
            * w strukturze.
            */

           memset(&addr, 0, sizeof(struct sockaddr_un));

           /* Łączenie gniazda z adresem gniazda */

           addr.sun_family = AF_UNIX;
           strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);

           ret = connect (data_socket, (const struct sockaddr *) &addr,
                          sizeof(struct sockaddr_un));
           if (ret == -1) {
               fprintf(stderr, "The server is down.\n");
               exit(EXIT_FAILURE);
           }

           /* Wysyłanie argumentów. */

           for (i = 1; i < argc; ++i) {
               ret = write(data_socket, argv[i], strlen(argv[i]) + 1);
               if (ret == -1) {
                   perror("write");
                   break;
               }
           }

           /* Żądanie wyniku. */

           strcpy (buffer, "END");
           ret = write(data_socket, buffer, strlen(buffer) + 1);
           if (ret == -1) {
               perror("write");
               exit(EXIT_FAILURE);
           }

           /* Otrzymanie wyniku. */

           ret = read(data_socket, buffer, BUFFER_SIZE);
           if (ret == -1) {
               perror("read");
               exit(EXIT_FAILURE);
           }

           /* Upewnienie się, że bufor kończy się 0. */

           buffer[BUFFER_SIZE - 1] = 0;

           printf("Result = %s\n", buffer);

           /* Zamknięcie gniazda. */

           close(data_socket);

           exit(EXIT_SUCCESS);
       }

       Przykład użycia SCM_RIGHTS można znaleźć w cmsg(3).

ZOBACZ TAKŻE

       recvmsg(2), sendmsg(2), socket(2), socketpair(2), cmsg(3),  capabilities(7),  credentials(7),  socket(7),
       udp(7)

O STRONIE

       Angielska  wersja  tej strony pochodzi z wydania 4.05 projektu Linux man-pages. Opis projektu, informacje
       dotyczące  zgłaszania   błędów,   oraz   najnowszą   wersję   oryginału   można   znaleźć   pod   adresem
       https://www.kernel.org/doc/man-pages/.

TŁUMACZENIE

       Autorami  polskiego  tłumaczenia  niniejszej  strony  podręcznika man są: Andrzej M. Krzysztofowicz (PTM)
       <ankry@mif.pg.gda.pl>, Robert Luberda <robert@debian.org> i Michał Kułach <michal.kulach@gmail.com>.

       Polskie tłumaczenie jest częścią  projektu  manpages-pl;  uwagi,  pomoc,  zgłaszanie  błędów  na  stronie
       http://sourceforge.net/projects/manpages-pl/. Jest zgodne z wersją  4.05 oryginału.