Cozi de mesaje
1. Introducere
2. Initializarea cozii de
mesaje
3. Trimiterea si primirea
mesajelor
4. Controlul cozilor de
mesaje
5.Exemple
O coada de mesaje este o lista inlantuita de mesaje stocata in nucleu si identificata printr-un identificator al cozii de mesaje. Sincronizarea intre procesele care transmit mesaje si cele care receptioneaza se face pe principiul producator/consumator, controlat de nucleul sistemului de operare.. Doua sau mai multe procese comunica intre ele folosind una sau mai multe cozi circulare de mesaje, gestionate de sistemul de operare. Procesele care asteapta mesaje se blocheaza pana la aparitia mesajului dorit, iar cele care doresc sa transmita, pun mesajul in coada de mesaje (daca este loc) sau se blocheaza pana la eliberarea unui spatiu din coada. In acest fel are loc si o sincronizare a proceselor (cele care transmit cu cele care receptioneaza).
Fiecare mesaj primeste un
identificator (sau tip) astfel incat celelalte procese sa poata accesa mesagele
dorite.
Inainte ca un process sa poate primi
sau trimite message, coada de mesaje trebuie initializata prin intermediul
functiei msgget. Pentru trimiterea si
a primirea mesajelor se folosesc functiile msgsnd() respective msgrcv().
2. Initializarea Cozii de
Mesaje
Se realizeaza prin intermediul functiei msgget() avand urmatorul prototip:
int msgget(key_t key, int
msgflg)
Valoarea returnata:
ID cozii noi sau vechi (dacă coada exista) in caz de success
-1 în caz de eroare.
Parametrii:
key - argumentul key este cheia ataşată cozii de mesaje
Nota: Functiile pentru initializarea sau
accesarea unor servicii IPC-ul au un argument de tip key_t key (la baza
key_t este un tip int definit in <sys/types.h>)
msgflg - indică acţiuna de creare şi drepturile de acces la coada de mesaje.
Nota: Pentru deschiderea unei cozi existente, msflag va avea valoarea 0. Pentru creare, msflag va avea o valoare de forma:
IPC_CREAT | IPC_EXCL | drepturi_de_acces
Daca msflag contine flagul IPC_CREAT apelul functiei incearca sa creeze coada de mesaje daca aceasta nu exista deja.
Daca si flagul IPC_EXCL este prezent functia esueaza daca coada de mesaje exista deja. (aceasta e folositor cand se doreste ca un singur proces sa creeze coada)
Bytes cei mai putin semnificativi reprezinta drepturile de acces la coada de mesaje.
Ex:
#include <sys/ipc.h>;
#include <sys/msg.h>;
...
key_t key; /* cheia cozii de mesaje
*/
int msgflg /* flagurile */
int msqid; /* id-ul cozii de
mesaje*/
...
key = ...
msgflg = ...
if ((msqid = msgget(key, msgflg)) ==
-1)
{
perror("msgget: msgget failed");
exit(1);
}
else
printf(
“msgget succeeded");
...
Nota: o modalitate simpla de a asocia unei cozi de mesaje o cheie e folosind functia ftok() care converteste o cale intr-o cheie.
Exemplul urmator initializeaza o coada de mesaje daca aceasta nu
exista deja:
msqid = msgget(ftok("/tmp",
key), (IPC_CREAT |
IPC_EXCL | 0400));
Primul argument se evalueza la o variabila de tip key_t iar
al doilea argument reprezinta flagurile de control si drepturile de access.
3. Trimiterea si primirea
mesajelor
Funtiile msgsnd() and msgrcv() sunt cele care se ocupa de trimiterea respectiv primirea mesajelor.
Prototipul lor este:
int msgsnd(int msqid, const void *msgp, size_t
msgsz, int msgflg);
int msgrcv(int msqid, void *msgp, size_t msgsz,
long msgtyp, int msgflg);
unde:
msqid
- trebuie sa fie id-ul unei
cozi existente
msgp
– este un pointer la o structura care contine tipul mesajului si textul. Structura urmatoare este un exemplu de o asemenea structura:
struct mymsg
{
long mtype; /* tipul mesajului
*/
char mtext[1000]; /* mesaj de lungime 1000
*/
}
msgsz
– reprezinta lungimea mesajului in bytes
msgtype
– tipul mesajului pe care sa il primeste (tip care a fost precizat la trimiterea
mesajului)
msgflg
– specifica actiunea care va avea loc daca una din urmatoarele e adevarata:
·
Numarul de bytes din coada e egal cu msg_qbytes
·
Coada e plina
Daca flagul IPC_NOWAIT este
setat, mesajul nu va fi trimis iar apelul va reveni la procesul
appelant.
Daca flagul IPC_NOWAIT nu este setat, procesul isi
suspenda activitatea pana cand apare unul din urmatoarele
avenimente:
·
Dispare conditia din cauza careie se
asteapta
·
Coada de mesaje este
stearsa
·
Procesul apelant primeste un semnal care trebuie prins. Mesajul nu este trimis iar
procesul isi reia executia
Ex:
#include <sys/types.h>
#include
<sys/ipc.h>
#include
<sys/msg.h>
...
int
msgflg; /* flagurile pt operatii */
struct msgbuf *msgp; /* pointer la bufferul de mesaje
*/
int
msgsz; /* dimensiunea mesajului*/
long
msgtyp; /* tipul mesajului */
int
msqid /* id-ul cozii de mesaje */
...
msgp
= (struct msgbuf *)malloc((unsigned)(sizeof(struct msgbuf)
-
sizeof msgp->mtext + maxmsgsz));
if
(msgp == NULL) {
printf("msgop: %s %d byte messages.\n","could not allocate
message buffer for", maxmsgsz);
exit(1);
...
msgsz = ...
msgflg = ...
if
(msgsnd(msqid, msgp, msgsz, msgflg) == -1)
perror("msgop: msgsnd failed");
...
msgsz = ...
msgtyp = first_on_queue;
msgflg = ...
if
(rtrn = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) == -1)
perror("msgop: msgrcv failed");
...
4. Controlul cozilor de
mesaje
Functia msgctl()
modifica drepturile de access si alte caracteristici ale cozilor de mesaje.
Aceasta functie poate fi folosita de creatorul cozii de mesaje
sau de alte procese autorizate.
Prototipul functiei este:
int msgctl(int msqid, int cmd, struct msqid_ds
*buf )
Valoare returnata: 0 în caz de succes şi -1 în caz de
eroare.
Parametrii:
msgid- id-ul unei cozi de mesaje
existenta
cmd- poate avea una din
urmatoarele valori:
IPC_STAT
Conţinutul structurii asociate
cozii de mesaje este transferat la adresa referită de
buf. (Procesul trebuie sa aiba drepturi de citire ca sa poate apela aceasta
functie)
IPC_SET
Permite
modificarea câmpurilor msg_perm.uid, msg_perm.gid, msg_perm.mode (ultimii
9 biţi care indică drepturile de acces). Campul msg_qbytes poate
fi modificat numai de un proces al superuser-ului. Structura de date asociată cozii de
mesaje este actualizata conform informatiilor de le
adresa referită de buf. Actualizarea poate fi facuta de un proces care apartine superuser-ului sau unui utilizator ce
are ID utilizatorului efectiv egal cu msg_perm.uid sau
msg_perm.cuid.
IPC_RMID
sterge
coada de mesaje specificata prin msgid
message_send.c
-- creaza
o coada de mesaje si trimite un mesaj in aceasta coada
message_rec.c
-- citeste mesajul din coada
message_send.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#define MSGSZ 128
/*
* Declara
structura mesajului
*/
typedef struct msgbuf
{
long mtype;
char mtext[MSGSZ];
} message_buf;
main()
{
int msqid;
int msgflg = IPC_CREAT | 0666;
key_t key;
message_buf sbuf;
size_t buf_length;
/*
* cheia cozii de mesaje va fi
1234
*/
key = 1234;
printf("\nmsgget: Calling
msgget(%#lx,\%#o)\n",key, msgflg);
if ((msqid = msgget(key, msgflg )) < 0)
{
perror("msgget");
exit(1);
}
else
printf("msgget: msgget succeeded: msqid = %d\n",
msqid);
/*
* se trimite un mesaj de tipul 1
*/
sbuf.mtype = 1;
printf("msgget: msgget succeeded: msqid = %d\n",
msqid);
strcpy(sbuf.mtext, "HelloJ
Nice to meet youJ");
printf("msgget: msgget succeeded: msqid = %d\n",
msqid);
buf_length = strlen(sbuf.mtext) + 1
;
/*
* trimitem mesajul
*/
if (msgsnd(msqid, &sbuf, buf_length,
IPC_NOWAIT) < 0) {
printf ("%d, %d, %s, %d\n", msqid, sbuf.mtype, sbuf.mtext,
buf_length);
perror("msgsnd");
exit(1);
}
else
printf("Message: \"%s\" Sent\n", sbuf.mtext);
exit(0);
}
Nota:
- Coada de mesaje este creata cu cheia key=1234 si flagurile msgflg =
IPC_CREATE | 0666 prin care se creaza coada de mesaje si se dau drepturi de
scriere si de citire la toate procesele.
- Un mesaj avand tipul sbuf.mtype=
1 este trimis in coada de mesaje cu textul “HelloJ
Nice to meet youJ”
message_rec.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define MSGSZ 128
/*
* Declararea
structurii de mesaje
*/
typedef struct msgbuf
{
long mtype;
char mtext[MSGSZ];
} message_buf;
main()
{
int msqid;
key_t key;
message_buf
rbuf;
/*
* setarea cheii
*/
key = 1234;
if ((msqid = msgget(key, 0666)) < 0)
{
perror("msgget");
exit(1);
}
/*
* primirea unui mesaj de tipul 1
*/
if (msgrcv(msqid, &rbuf, MSGSZ, 1, 0) <
0) {
perror("msgrcv");
exit(1);
}
/*
* Afisarea mesajului primit
*/
printf("%s\n", rbuf.mtext);
exit(0);
}
Nota:
- Coada de mesaje
este deschisa cu aceasi cheie folosita in
message_send.c
- Un mesaj de tipul 1 este primit din coada de mesaje si pus in rbuf.mtext.