msgrcv

MSGOP(2)                 Podręcznik programisty Linuksa                 MSGOP(2)



NAZWA
       msgrcv, msgsnd - przekazywanie komunikatów kolejki Systemu V

SKŁADNIA
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

OPIS
       The msgsnd()  and msgrcv()  system calls are used to send messages to,
       and receive messages from, a System V message queue.  The calling process
       must have write permission on the message queue in order to send a
       message, and read permission to receive a message.

       Parametr msgp jest wskaźnikiem do zdefiniowanej przez proces wywołujący
       struktury, której ogólna postać wygląda tak:

           struct msgbuf {
               long mtype;       /* typ wiadomości, musi być > 0 */
               char mtext[1];    /* dane wiadomości */
           };

       Pole mtext jest tablicą (lub inna strukturą) o rozmiarze określonym przez
       msgsz, będącym nieujemną liczbą całkowitą. Dozwolone są komunikaty o
       zerowej długości (tzn. niezawierające pola mtext). Wartość pola mtype
       musi być liczbą ściśle dodatnią, która może służyć procesowi
       odbierającemu komunikaty do filtrowania kolejki (zobacz opis msgrcv()
       poniżej).

   msgsnd()
       Wywołanie systemowe msgsnd() dołącza kopię komunikatu wskazywanego przez
       msgp do kolejki o identyfikatorze określonym przez msqid.

       Gdy w kolejce jest wystarczająco dużo miejsca, to msgsnd() natychmiast
       kończy się pomyślnie. (Pojemność kolejki określona jest w polu msg_qbytes
       struktury danych stowarzyszonej z kolejką. Podczas tworzenia kolejki polu
       temu jest przypisywana wartość początkowa wynosząca MSGMNB bajtów, lecz
       ograniczenie to może zostać zmienione za pomocą msgctl(2)). Kolejka
       komunikatów jest uważana za pełną w jednym z następujących przypadków:

       • Dodanie nowego komunikatu do kolejki spowoduje, że suma bajtów w
         kolejki przekroczy maksymalny rozmiar kolejki (pole msg_qbytes).

       • Dodanie kolejnego komunikatu do kolejki spowoduje, że całkowita liczba
         komunikatów w kolejce przekroczy maksymalny rozmiar kolejki (pole
         msg_qbytes). To sprawdzenie jest konieczne aby zapobiec umieszczaniu w
         kolejce nieograniczonej liczby komunikatów o zerowej długości. Choć
         takie komunikaty nie zawierają danych, to wciąż zajmują (zablokowaną)
         pamięć jądra.

       Jeśli w kolejce obecna jest niewystarczająca ilość wolnego miejsca, to
       domyślne zachowaniem msgsnd() jest blokada do momentu uzyskania wolnej
       przestrzeni. Jeśli w msgflg określono IPC_NOWAIT, to zamiast tego
       wywołanie zwróci błąd EAGAIN.

       Wstrzymane wywołanie msgsnd() może się także nie powieść, jeżeli:

       • kolejka zostanie usunięta z systemu - w tym przypadku wywołanie
         systemowe zgłosi błąd, przypisując zmiennej errno wartość EIDRM;

       • zostanie przechwycony sygnał - wtedy wywołanie to powoduje przypisanie
         zmiennej errno wartości EINTR; patrz signal(7) (msgsnd() po przerwaniu
         przez obsługę sygnału nie jest nigdy automatycznie restartowane,
         niezależnie od ustawienia znacznika SA_RESTART podanego podczas
         ustanawiania funkcji obsługi sygnału).

       Jeśli operacja zakończy się pomyślnie, to struktura danych opisująca
       kolejkę zostanie zmodyfikowana w następujący sposób:

       • msg_lspid przypisany zostanie identyfikator procesu wykonującego tę
         operację.

       • msg_qnum zostanie zwiększone o 1.

       • msg_stime zostanie przypisany bieżący czas.

   msgrcv()
       Wywołanie systemowe msgrcv usuwa komunikat z kolejki określonej przez
       msqid i umieszcza go w buforze wskazywanym przez parametr msgp.

       Parametr msgsz określa maksymalny rozmiar w bajtach pola mtext struktury
       wskazywanej przez parametr msgp. Jeśli dane komunikatu zajmują więcej
       bajtów niż msgsz, to wynik zależy od tego, czy w msgflg przekazano
       znacznik MSG_NOERROR. Jeżeli podano MSG_NOERROR, to tekst komunikatu
       zostanie obcięty (obcięta część zostanie utracona); jeżeli MSG_NOERROR
       nie występuje, to komunikat nie jest usuwany z kolejki, a wywołanie
       systemowe kończy się błędem, zwracając wartość -1 i ustawiając errno na
       E2BIG.

       Jeżeli podano MSG_COPY w msgflg (zob. poniżej), parametr msgtyp określa
       rodzaj komunikatu w następujący sposób:

       • Jeśli msgtyp jest równy 0, to czytany jest pierwszy komunikat z
         kolejki.

       • Jeśli msgtyp ma wartość większą niż 0, to z kolejki odczytywany jest
         pierwszy komunikat o typie msgtyp, chyba że w parametrze msgflg
         zostanie ustawiony znacznik MSG_EXCEPT, co spowoduje, że z kolejki
         zostanie odczytany pierwszy komunikat o typie różnym od msgtyp.

       • Jeśli msgtyp ma wartość mniejszą niż 0, to z kolejki zostanie odczytany
         pierwszy komunikat o najniższym numerze typu, mniejszym lub równym
         wartości bezwzględnej msgtyp.

       Parametr msgflg jest maską bitową, utworzoną jako alternatywa (OR) zera
       lub więcej  następujących znaczników:

       IPC_NOWAIT
              Nie wstrzymuje pracy procesu, jeśli w kolejce nie ma komunikatów
              odpowiedniego typu. Wywołanie systemowe zwróci wówczas błąd,
              przypisując zmiennej errno wartość ENOMSG.

       MSG_COPY (od Linuksa 3.8)
              Nieniszcząco pobiega kopię komunikatu w pozycję porządkową w
              kolejce określoną przez msgtyp (komunikaty są pomyślane do
              numerowania od 0).

              Tę flagę należy podać w połączeniu z IPC_NOWAIT, co skutkuje tym,
              że jeśli w danej pozycji nie ma dostępnego komunikatu, to
              wywołanie natychmiast zwraca błąd ENOMSG. Ponieważ zmienia to
              znaczenie msgtyp w różny sposób, MSG_COPY i MSG_EXCEPT nie
              mogą być podane równocześnie w msgflg.

              Flaga MSG_COPY została dodana dla zaimplementowania w jądrze
              funkcji przywracania do punktu kontrolnego (checkpoint-restore) i
              jest dostępna wyłącznie wtedy, jeśli jądro zbudowano z opcją
              CONFIG_CHECKPOINT_RESTORE.

       MSG_EXCEPT
              Użyte z parametrem msgtyp większym od 0, spowoduje odczytanie z
              kolejki pierwszego komunikatu o typie różnym od msgtyp.

       MSG_NOERROR
              Spowoduje obcięcie komunikatu, jeśli jego dane są dłuższe niż
              msgsz bajtów.

       Jeśli w kolejce nie ma komunikatu spełniającego te warunki, a znacznik
       IPC_NOWAIT nie został ustawiony w msgflg, to proces zostanie wstrzymany,
       dopóki nie nastąpi jedno z poniższych zdarzeń:

       • Komunikat odpowiedniego typu zostanie umieszczony w kolejce.

       • Kolejka zostanie usunięta z systemu. W tym przypadku wywołanie
         systemowe zgłosi błąd, przypisując zmiennej errno wartość EIDRM.

       • Proces wywołujący przechwytuje sygnał. W takim przypadku wywołanie
         systemowe kończy się niepowodzeniem, ustawiając errno na EINTR.
         (msgrcv() po przerwaniu przez obsługę sygnału nie jest nigdy
         automatycznie restartowane, niezależnie od ustawienia znacznika
         SA_RESTART podczas ustanawiania funkcji obsługi sygnału).

       Jeśli operacja zakończy się pomyślnie, to struktura danych opisująca
       kolejkę zostanie zmodyfikowana w następujący sposób:

              msg_lrpid przyjmie wartość równą identyfikatorowi wołającego
              procesu

              msg_qnum zostanie zmniejszone o 1.

              msg_rtime zostanie przypisany bieżący czas.

WARTOŚĆ ZWRACANA
       W przypadku niepowodzenia obydwa wywołania zwrócą -1 i przypiszą zmiennej
       errno wartość określającą rodzaj błędu. W przeciwnym przypadku, msgsnd()
       zwróci 0, a msgrvc() zwróci liczbę bajtów skopiowanych z kolejki do
       tablicy mtext.

BŁĘDY
       Jeśli wywołanie msgsnd() się nie powiedzie, to zmienna errno przyjmie
       jedną z poniższych wartości:

       EACCES The calling process does not have write permission on the message
              queue, and does not have the CAP_IPC_OWNER capability in the user
              namespace that governs its IPC namespace.

       EAGAIN Komunikat nie może zostać wysłany z powodu ograniczenia msg_qbytes
              dotyczącego kolejki, a nie przekazano znacznika IPC_NOWAIT w
              parametrze mgsflg.

       EFAULT Adres wskazywany przez msgp jest niedostępny.

       EIDRM  Kolejka komunikatów została usunięta.

       EINTR  Podczas oczekiwania na zwolnienie miejsca w kolejce, proces
              przechwycił sygnał.

       EINVAL Niewłaściwa wartość msqid, mtype (powinna być dodatnia) lub msgsz
              (powinna być większa lub równa 0 i mniejsza lub równa MSGMAX).

       ENOMEM Brak w systemie pamięci na skopiowanie komunikatu wskazywanego
              przez msgp.

       Jeśli wywołanie msgrcv() się nie powiedzie, to zmiennej errno zostanie
       przypisana jedna z poniższych wartości:

       E2BIG  Tekst komunikatu jest dłuższy niż msgsz i nie ustawiono znacznika
              MSG_NOERROR w parametrze msgflg.

       EACCES The calling process does not have read permission on the message
              queue, and does not have the CAP_IPC_OWNER capability in the user
              namespace that governs its IPC namespace.

       EFAULT Adres wskazywany przez msgp jest niedostępny.

       EIDRM  Proces oczekiwał na komunikat, ale w międzyczasie kolejka została
              usunięta.

       EINTR  Proces przechwycił sygnał podczas oczekiwania na odebranie
              komunikatu; patrz signal(7).

       EINVAL msqid był niepoprawny lub msgsz był mniejszy od 0.

       EINVAL (od Linuksa 3.14)
              msgflg określono jako MSG_COPY, ale nie IPC_NOWAIT.

       EINVAL (od Linuksa 3.14)
              msgflg określono jako MSG_COPY i MSG_EXCEPT.

       ENOMSG Znacznik IPC_NOWAIT został przekazany w msgflg, ale w kolejce nie
              ma komunikatu żądanego typu.

       ENOMSG IPC_NOWAIT i MSG_COPY zostały określone w msgflg, a kolejka
              zawiera mniej niż msgtyp komunikatów.

       ENOSYS (od Linuksa 3.8)
              MSG_COPY zostało określone w msgflg, a jądro zostało
              skonfigurowane bez opcji CONFIG_CHECKPOINT_RESTORE.

ZGODNE Z
       POSIX.1-2001, POSIX.1-2008, SVr4.

       Znaczniki MSG_EXCEPT i MSG_COPY są charakterystyczne dla Linuksa, ich
       definicje można pobrać przez zdefiniowane makra testującego funkcje
       _GNU_SOURCE.

UWAGI
       Dołączenie <sys/types.h> i <sys/ipc.h> nie jest wymagane na Linuksie ani
       przez żadną z wersji POSIX. Jednak niektóre stare implementacje wymagają
       dołączenia tych plików nagłówkowych, SVID również dokumentuje ich
       dołączenie. Aplikacje które mają być przenośne na tego typu stare systemy
       mogą wymagać dołączenia omawianych plików nagłówkowych.

       Parametr msgp jest deklarowany jako struct msgbuf * w glibc 2.0 i glibc
       2.1. W glibc 2.2 i późniejszych jest deklarowany jako void *, zgodnie z
       wymaganiami SUSv2 i SUSv3.

       Wywołania msgsnd() dotyczą następujące ograniczenia systemowe:

       MSGMAX Maksymalny rozmiar tekstu komunikatu, w bajtach: (domyślna
              wartość: 8192 bajty). Pod Linuksem ten limit można odczytać i
              modyfikować, używając pliku /proc/sys/kernel/msgmax.

       MSGMNB Maksymalna liczba bajtów która może być przechowywana w kolejce
              komunikatów (domyślna wartość: 16384 bajtów). Pod Linuksem można
              ten limit odczytać i zmienić, używając pliku
              /proc/sys/kernel/msgmnb. Proces uprzywilejowany (w Linuksie:
              proces z przywilejem CAP_SYS_RESOURCE) może zwiększyć rozmiar
              kolejki komunikatów poza MSGMNB za pomocą operacji IPC_SET
              msgctl(2).

       W tej implementacji nie ma jawnego systemowego ograniczenia liczby
       komunikatów przechowywanych w kolejce (MSGTQL) i na rozmiar obszaru (w
       bajtach) przeznaczonego na komunikaty (MSGPOOL).

BŁĘDY
       W Linuksie 3.13 i wcześniejszych, jeśli msgrcv() było wywołane ze
       znacznikiem MSG_COPY, lecz bez IPC_NOWAIT, a kolejka komunikatów
       zawierała mniej niż msgtyp komunikatów, to wywołanie było zablokowane aż
       do zapisania kolejnego komunikatu do kolejki. W tym momencie wywołanie
       zwracało kopię komunikatu bez względu na to czy komunikat był w pozycji
       msgtyp. Błąd ten został naprawiony w jądrze Linux 3.14.

       Podanie zarówno w msgflg zarówno MSG_COPY jak i MSC_EXCEPT jest błędem
       logicznym (ponieważ oba te znaczniki wymagają innej interpretacji
       msgtyp). W Linuksie 3.13 błąd ten nie był diagnozowany przez msgsrv().
       Zostało to naprawione w jądrze Linux 3.14.

PRZYKŁADY
       Program poniżej demonstruje użycie msgsnd() i msgrcv().

       Przykładowy program jest początkowo uruchomiony z opcją -s, aby wysłać
       komunikat, a następnie ponownie z opcją -r, aby otrzymać komunikat.

       Poniższa sesja powłoki pokazuje przykładowy przebieg programu:

           $ ./a.out -s
           sent: a message at Wed Mar  4 16:25:45 2015

           $ ./a.out -r
           message received: a message at Wed Mar  4 16:25:45 2015

   Kod źródłowy programu

       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <time.h>
       #include <unistd.h>
       #include <errno.h>
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       struct msgbuf {
           long mtype;
           char mtext[80];
       };

       static void
       usage(char *prog_name, char *msg)
       {
           if (msg != NULL)
               fputs(msg, stderr);

           fprintf(stderr, "Uzycie: %s [opcje]\n", nazwa_prog);
           fprintf(stderr, "Opcje:\n");
           fprintf(stderr, "-s        wysyła komunikat przez msgsnd()\n");
           fprintf(stderr, "-r        odczytuje komunikat przez msgrcv()\n");
           fprintf(stderr, "-t        typ komunikatu (domyślnie: 1)\n");
           fprintf(stderr, "-k        klucz kolejki komunikatu (domyślnie: 1234)\n");
           exit(EXIT_FAILURE);
       }

       static void
       send_msg(int qid, int msgtype)
       {
           struct msgbuf msg;
           time_t t;

           msg.mtype = msgtype;

           time(&t);
           snprintf(msg.mtext, sizeof(msg.mtext), "wiadomość o %s",
                   ctime(&t));

           if (msgsnd(qid, (void *) &msg, sizeof(msg.mtext),
                       IPC_NOWAIT) == -1) {
               perror("błąd msgsnd");
               exit(EXIT_FAILURE);
           }
           printf("wysłano: %s\n", msg.mtext);
       }

       static void
       get_msg(int qid, int msgtype)
       {
           struct msgbuf msg;

           if (msgrcv(qid, (void *) &msg, sizeof(msg.mtext), msgtype,
                      MSG_NOERROR | IPC_NOWAIT) == -1) {
               if (errno != ENOMSG) {
                   perror("msgrcv");
                   exit(EXIT_FAILURE);
               }
               printf("Brak komunikatu dostępnego dla msgrcv()\n");
           } else
               printf("komunikat otrzymano: %s\n", msg.mtext);
       }

       int
       main(int argc, char *argv[])
       {
           int qid, opt;
           int mode = 0;               /* 1 = wysłanie, 2 = otrzymanie */
           int msgtype = 1;
           int msgkey = 1234;

           while ((opt = getopt(argc, argv, "srt:k:")) != -1) {
               switch (opt) {
               case 's':
                   mode = 1;
                   break;
               case 'r':
                   mode = 2;
                   break;
               case 't':
                   msgtype = atoi(optarg);
                   if (msgtype <= 0)
                       usage(argv[0], "opcja -t musi być większa od 0\n");
                   break;
               case 'k':
                   msgkey = atoi(optarg);
                   break;
               default:
                   usage(argv[0], "Nierozpoznana opcja\n");
               }
           }

           if (mode == 0)
               usage(argv[0], "musi być opcją -s albo -r\n");

           qid = msgget(msgkey, IPC_CREAT | 0666);

           if (qid == -1) {
               perror("msgget");
               exit(EXIT_FAILURE);
           }

           if (mode == 2)
               get_msg(qid, msgtype);
           else
               send_msg(qid, msgtype);

           exit(EXIT_SUCCESS);
       }

ZOBACZ TAKŻE
       msgctl(2), msgget(2), capabilities(7), mq_overview(7), sysvipc(7)

O STRONIE
       Angielska wersja tej strony pochodzi z wydania 5.08 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 są: Rafał
       Lewczuk <R.Lewczuk@elka.pw.edu.p>, Andrzej Krzysztofowicz
       <ankry@green.mf.pg.gda.pl>, Robert Luberda <robert@debian.org> i Michał
       Kułach <michal.kulach@gmail.com>

       Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o
       warunkach licencji można uzyskać zapoznając się z GNU General Public
       License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ
       ODPOWIEDZIALNOŚCI.

       Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres
       <manpages-pl-list@lists.sourceforge.net>.



Linux                          11 kwietnia 2020 r.                      MSGOP(2)