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);
Wywołań systemowych msgsnd() i msgrcv() używa się do - odpowiednio - wysyłania komunikatów do kolejki komunikatów i odbierania komunikatów z kolejki Systemu V. Aby wysłać komunikat, proces wywołujący musi mieć uprawnienie do zapisu na kolejce komunikatów, a aby odebrać komunikat - uprawnienie do odczytu kolejki.
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:
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.
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, (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); }
msgctl(2), msgget(2), capabilities(7), mq_overview(7), svipc(7)
Angielska wersja tej strony pochodzi z wydania 4.07 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 man są: Rafał Lewczuk (PTM) <R.Lewczuk@elka.pw.edu.p>, Andrzej 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.07 oryginału.
2015-08-08 | Linux |