Cozi de mesaje

1. Introducere

2. Initializarea cozii de mesaje

3. Trimiterea si primirea mesajelor

4. Controlul cozilor de mesaje

5.Exemple

 

1. Introducere

 

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

 

5. Exemple

 

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.