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.