MSGOP(2) | Podręcznik programisty Linuksa | MSGOP(2) |
msgrcv, msgsnd - przekazywanie komunikatów kolejki Systemu V
#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);
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).
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:
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:
Jeśli operacja zakończy się pomyślnie, to struktura danych opisująca kolejkę zostanie zmodyfikowana w następujący sposób:
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:
Parametr msgflg jest maską bitową, utworzoną jako alternatywa (OR) zera lub więcej następujących znacznikó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ń:
Jeśli operacja zakończy się pomyślnie, to struktura danych opisująca kolejkę zostanie zmodyfikowana w następujący sposób:
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.
Jeśli wywołanie msgsnd() się nie powiedzie, to zmienna errno przyjmie jedną z poniższych wartości:
Jeśli wywołanie msgrcv() się nie powiedzie, to zmiennej errno zostanie przypisana jedna z poniższych wartości:
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.
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:
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).
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.
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
#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, &msg, sizeof(msg.mtext),
IPC_NOWAIT) == -1) {
perror("msgsnd error");
exit(EXIT_FAILURE);
}
printf("sent: %s\n", msg.mtext); } static void get_msg(int qid, int msgtype) {
struct msgbuf msg;
if (msgrcv(qid, &msg, sizeof(msg.mtext), msgtype,
MSG_NOERROR | IPC_NOWAIT) == -1) {
if (errno != ENOMSG) {
perror("msgrcv");
exit(EXIT_FAILURE);
}
printf("No message available for msgrcv()\n");
} else
printf("message received: %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); }
msgctl(2), msgget(2), capabilities(7), mq_overview(7), sysvipc(7)
Angielska wersja tej strony pochodzi z wydania 5.10 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/.
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.
1 listopada 2020 r. | Linux |