escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_prev.gif  escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_up.gif  escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_next.gif  escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_home.gif

Üzenetsorok (message queues)

Folyamatok közti kommunikáció üzenetek (kis adatcsomagok) küldözgetésével...


 

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link.gif  Definíció

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link.gif  Műveletek üzenetsorokkal

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif  Létrehozás (msgget)

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif  Az üzenetsor adatainak lekérdezése, módosítása és törlése (msgctl)

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif  Üzenet küldése (msgsnd)

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif  Üzenet fogadása (msgrcv)

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link.gif  Példa

escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link.gif  Posix kiegészítés

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link.gif  Posix műveletek üzenetsorokkal

       escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif Létrehozás (mq_open)

       escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif Bezárás (mq_close)

       escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif Üzenet küldése  (mq_send)

       escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif Üzenet fogadása  (mq_receive)

       escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif Lecsatlakozás az üzenetsorról  (mq_unlink)

       escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif Üzenetsor tulajdonságainak lekérdezése  (mq_getattr)

       escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_link.gif Üzenetsor tulajdonságainak beállítása (mq_setattr)

escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link.gif Posix példa

 


 

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link_p.gif  Névvel ellátott csővezeték (FIFO)

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_book.gif  Definíció

A folyamatok közti kommunikáció egyik leghatékonyabb módja az üzenetsorok használata. Az üzenetsorokat a rendszer magja felügyeli. Egy ilyen sorban az adatok (vagyis az üzenetek) cirkulárisan közlekednek, a folyamatok közti szinkronizáció pedig a előállító/fogyasztó elv alapján valósul meg. Magyarul: ha az üzenetsor megtelt, az előállító leáll, ameddig egy fogyasztó ki nem olvas egy üzenetet, illetve ha az üzenetsor kiürült, a fogyasztónak kell várnia az első (neki címzett) üzenet érkezéséig.

Tehát az üzenetsor egy, a rendszer által tárol láncolt lista, amelynek jól meghatározott azonosítója van. Valamely folyamat egy üzenetsort egy kulcs segítségével azonosít. (Vigyázat! Nem tévesztendő össze az azonosító és a kulcs. A kulcsot mi választjuk, az azonosítót pedig a rendszer minden üzenetsorhoz automatikusan rendeli hozzá.)

Az a folyamat, amely üzenetet szeretne küldeni, előbb az adott kulcs alapján az msgget függvénnyel lekéri az üzenetsor azonosítóját, majd az msgsnd függvény segítségével elküldi az üzenetet. Az üzenet a sor végére kerül.

Az a folyamat, amely üzenetet szeretne fogadni, ugyanúgy lekérdezi a kulcs és az msgget függvény segítségével az üzenetsor azonosítóját, majd az msgrcv függvénnyel kiolvassa az üzenetet. Az üzenetsorból való olvasás nem feltétlenül a FIFO módszer szerint történik, ugyanis az mtype mező értékétől függően az üzeneteket tetszőleges sorrendben is kiolvashatjuk.

Egy üzenet szerkezete az msg.h állományban a következőképpen van definiálva:

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

Az mtype mező egy hosszú egész számot tartalmaz, amely az üzenet típusát jelképezi. Ezután következik a tulajdonképpeni üzenet (mtext), amely jelen esetben egyetlen karakterből áll. Amennyiben ennél hosszabb üzenetet szeretnénk egyszerre küldeni, mi is definiálhatunk hasonló szerkezetű struktúrákat. Például:

struct msg
{
  long tip;
  char uzenet[256];
};

Amint látjuk, az üzenetek szerkezete nem rögzített, de kötelezően tartalmazniuk kell a típust és magát az üzenetet. Ez utóbbi hossza mindig az alkalmazástól függ.

Minden üzenetsorhoz a rendszer hozzárendel egy msqid_ds típusú struktúrát, amelynek szerkezete:

struct msqid_ds
{
  struct ipc_perm msg_perm;  /*
definiálja a jogokat és a tulajdonost */
  struct msg *msg_first;    
/* mutató az első üzenetre */
  struct msg *msg_last;      /* mutató az utolsó üzenetre */
  ulong msg_cbytes;          /* sor bájtjainak száma */
  ulong msg_qnum;            /*
üzenetek száma a sorban */
  ulong msg_qbytes;          /*
maximális bájtok száma sorban */
  pid_t msg_lspid;           /*
utolsó msgsnd() pid-je */
  pid_t msg_lrpid;           /*
utolsó msgrcv() pid-je */
  time_t msg_stime;          /*
utolsó msgsnd() ideje */
  time_t msg_rtime;          /*
utolsó msgrcv() ideje */
  time_t msg_ctime;          /*
utolsó struktúramódosítás ideje */
};

ahol az ipc_perm struktúra a következőképpen definiált:

struct ipc_perm
{
  uid_t uid;                 /*
effektív felhasználó ID-je */
  gid_t gid;                 /*
effektív csoport ID-je */
  uid_t cuid;                /*
effektív létrehozó felhasználó ID-je */
  gid_t cgid;                /*
effektív létrehozó csoport ID-je */
  mode_t mode;               /*
hozzáférési jogok */
  ulong seq;                 /*
numǎr de secvenţǎ utilizare slot */
  key_t key;                 /*
kulcs */
};

Egy folyamat csak akkor férhet hozzá egy üzenetsorhoz ha:

- a folyamat a superuser-é,

- a felhasználó ID-je (uid) megegyezik az msg_perm.cuid-vel vagy az msg_perm.uid-vel és az msg_perm.mode tartalmazza a kívánt jogokat,

- a felhasználó csoportazonosítója (gid) megegyezik az msg_perm.cgid vagy msg_perm.gid értékek egyikével és az msg_perm.mode tartalmazza a kívánt jogokat,

- a felhasználó beleesik a "többi felhsználó" kategóriába és az msg_perm.mode tartalmazza a megfelelő jogokat.

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_book.gif  Műveletek üzenetsorokkal

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Létrehozás (msgget)

Az msgget rendszerfüggvény engedélyezi a folyamatnak, hogy létrehozzon egy üzenetsort felhasználva egy bizonyos kulcsot. Alakja:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int flg);

A függvény visszatérési értéke az újonnan létrehozott vagy egy régi üzenetsor azonosítója, ha a művelet sikerült, különben -1. A key változóban az üzenetsorhoz rendelt kulcsot kell megadni, míg az flg-ben a létrehozási tevékenységet és a hozzáférési jogokat. A kulcsot az üzenetsorhoz kapcsolódó összes folyamatnak ismernie kell.

Egy új üzenetsor létrehozása esetén az flg mezőt a következő formában kell megadni:

IPC_CREAT  |  IPC_EXCL  |  hozzáférési_jogok

Példaként hozzunk létre egy 2003 kulccsal rendelkező üzenetsort, és adjunk hozzá írási és olvasási jogot minden felhasználónak.

#define KEY 2003

int msgid;
msgid = msgget((key_t) KEY, IPC_CREAT | 0666);

Ha az üzenetsor már létezik, de meg szeretnénk határozni az azonosítóját (ID-ját), akkor az flg mezőbe 0-t írunk – ez esetben a függvény nem fog létrehozni új sort.

msgid = msgget((key_t) KEY, 0);

Létrehozáskor a társított adatstruktúra (msg_perm) mezői a következő információkkal töltődnek fel:

- msg_perm.cuid, msg_perm.uid – az msgget függvényt meghívó folyamathoz hozzárendelt felhasználó ID-ja,
- msg_perm.cgid, msg_perm.uid – az msgget függvényt meghívó folyamathoz hozzárendelt felhasználócsoport ID-ja,
- msg_perm.mode – az msgget függvény hívásakor megadott flg argumentum, amely a hozzáférési jogokat tartalmazza,
- msg_qnum, msg_lspid, msg_lrpid, msg_stime, msg_rtime – értéke 0,
- msg_ctime – az aktuális időt tartalmazza,
- msg_qbytes – azt a legnagyobb megengedett értéket tartalmazza, amely a rendszer létrehozásakor volt rögzítve.

Az msgget függvény hívásakor visszaadott azonosítót az üzenetsorral dolgozó függvények használják.

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Az üzenetsor adatainak lekérdezése, módosítása és törlése (msgctl)

Az msgctl függvény az üzenetsorok szintjén az információk lekérdezésére, módosítására és törlésére használható. Szintaxisa:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msgid, int cmd, struct msqid_ds *buf);

A függvény visszatérési értéke 0, ha a művelet sikeres volt, ellenkező esetben -1. Az msgid paraméter az msgget függvény által meghatározott üzenetsor azonosítója.

A cmd argumentum a kívánt műveletet határozza meg és a következő értékeket veheti fel:

- IPC_STATaz üzenetsorhoz rendelt struktúra tartalma a buf változóba kerül,

- IPC_SETaz üzenetsorhoz rendelt struktúrát frissíti a buf által megadott struktúrával,

- IPC_RMIDaz üzenetsorhoz rendelt struktúrát törli; a művelet azonnali és minden folyamat, amely ezt a sort használja az errno=EIDRM üzenetet kapja; ez esetbe a buf argumentumnak a NULL értéket kell adni.

Példa:

#define KEY 2003

msgid = msgget((key_t) KEY, 0);
msgctl(msgid, IPC_RMID, NULL);

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Üzenet küldése (msgsnd)

Az msgsnd függvény egy már létrehozott üzenetsorba ír egy adott üzenetet. Szintaxisa:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msgid, const void *addr, size_t nbytes, int flg);

A függvény visszatérési értéke 0, ha a művelet sikeres volt, ellenkező esetben -1. Az msgid az msgget által meghatározott üzenetsor azonosítója. Az addr pointer típusú argumentum az üzenetre mutat. Ez lehet void vagy msgbuf típusú. Az előbbi esetben az üzenet szerkezete tetszőleges lehet. Az nbytes megadja az üzenet tartalmának a hosszát (nem az egész üzenetét!). Az flg paraméterben megadhatjuk, hogy a rendszer hogyan viselkedjen, ha az üzenetet nem lehet beírni a sorba. Például, ha a sor megtelt és az IPC_NOWAIT opciót választottuk, akkor a folyamat nem áll le, hanem visszatér a függvényből, és az errno az EAGAIN hibaüzenetet fogja tartalmazni.

A következő példa egy üzenetnek a sorba való beírását mutatja be:

#define KEY 2003
struct msgbuf uzenet;
char *uzen = "probauzenet";

msgid = msgget((key_t) KEY, 0);
uzenet.mtype = 100;
strcpy(uzenet.mtext, uzen);
msgsnd(msgid, &uzenet, strlen(uzen), IPC_NOWAIT);

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Üzenet fogadása (msgrcv)

Az msgrcv függvény feladata kiolvasni egy üzenetet az üzenetsorból. A paraméterek segítségével megadhatjuk, hogy milyen típusú üzeneteket fogadjon. Alakja:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgrcv(int msgid, void *addr, size_t nbytes, long msgtype, int flg);

A függvény sikeres olvasás esetén visszaadja a kiolvasott bájtok számát, különben a -1 értéket. Az msgid az msgget által meghatározott üzenetsor azonosítója. Az addr pointer a kapott üzenetre mutat.

Az nbytes a lekérdezett üzenet maximális hossza bájtokban. Az üzenet valós mérete különbözhet az nbytes-ban megadottól. Ha az üzenet hossza kisebb a megadott maximális méretnél, akkor minden OK. Ha viszont átlépi az nbytes határt, akkor két eset lehetséges:

a. Ha az MSG_NOERROR be van állítva, az üzenet megcsonkul, de nem kapunk hibaüzenetet.

b. Ha az MSG_NOERROR nincs beállítva, a függvény nem olvassa ki az üzenetet, a függvény hibát ad, és az errno változó értéke E2BIG lesz.

Az msgtype paraméter határozza meg a kiolvasandó üzenet típusát. 3 eset lehetséges:

a. msgtype = 0  –  a sor első üzenetét olvassa ki,

b. msgtype > 0  –  a sor első msgtype típusú üzenetét olvassa ki,

c. msgtype < 0  –  a sor legkisebb, de az abs(msgtype)-nál nagyobb vagy azzal egyenlő értékű üzenetét olvassa ki.

Az flg argumentummal megadhatjuk, hogy a rendszer hogyan viselkedjen, ha a függvény meghívásának feltételei nem teljesülnek. Az előbb bemutattuk az MSG_NOERROR használatát. Következzen az IPC_NOWAIT-é. Szintén két eset lehetséges:

a. Ha az IPC_NOWAIT be van állítva, a folyamat nem várja meg az óhajtott üzenetnek a sorban való elhelyezését. A függvény hibát ad, és az errno értéke ENOMSG lesz.

b. Ha az IPC_NOWAIT nincs beállítva, a folyamat addig várakozik, ameddig kerül egy megfelelő üzenet, ameddig a sor megsemmisül (errno=EIDRM), vagy egy jelzés érkezik (errno=EINTR).

A következő programrészlet példa egy üzenet kiolvasására:

#define KEY 2003
struct msgbuf uzenet;

msgid = msgget((key_t) KEY, 0);
msgrcv(msgid, &uzenet, 25, long(100), IPC_NOWAIT | MSG_NOERROR);

Ha az üzenetsorba bekerülő adatok típusai megegyeznek, akkor az üzenetsorok tulajdonképpen FIFO állományként működnek.

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_book.gif  Példa(Letöltés)

Hozzunk létre egy kliens-szerver rendszert! A kliensfolyamat a parancssorból beolvas egy tevékenységkódot (pl. kliens 2), majd ezt egy üzenetsoron keresztül elküldi a szervernek. A visszakapott választ a képernyőre írja. A szerverfolyamat kiolvassa az üzenetsorból a tevékenységkódot, elvégzi a tevékenységet, majd jelentést küld a kliensnek.

Az egyszerűség kedvéért a közös adatokat (így az üzenet struktúráját is) egy külön fejléc állományban tároljuk, amelyet mind a kliens, mind a szerver el tud majd érni.

mes.h

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

#define KEY 958320  /* az üzenetsor kulcsa */

 

#define READ 1 /* tevékenységkódok elnevezései */

#define WRITE 2

 

typedef struct{     /* az üzenet struktúrája */

  long mtip;  /* üzenet típusa */

  int pid;    /* küldő folyamat azonosítója */

  int cod_op; /* kliens üzenete; tevékenységkód */

  char mtext[13];   /* szerver üzenete; tev. elnevezése */

} MESSAGE;

 

A kliens első lépésben a parancssorból beolvas egy tevékenységkódot. Egyetlen üzenetsort használunk, amelyen keresztül minden kliens elküldheti a kéréseit a szerver felé, és amelyen a válasz is érkezik. Azért, hogy egy kliens megkapja a neki címzett választ, csak azon üzeneteket fogja kiolvasni a sorból, amelyek típusa éppen megegyezik a saját pid-jével. Éppen ezért a kéréssel egyidőben minden kliensnek el kell küldenie az azonosítóját is.

kliens.c

#include "mes.h"    /* a közös mes állomány */

 

int msgid;    /* üzenetsor azonosítója */

 

void main(int argc, char **argv)

{

  pid_t pid;  /* folyamatazonosító */

  MESSAGE mesp;     /* üzenet */

 

  if (argc != 2){   /* hibás argumentumok */

        printf("hasznalat: c <cop_op>\n");

        exit(1);   

  }

  if ((msgid = msgget((key_t) KEY, 0666)) < 0){

        perror("In msgget()");  /* üzenetsor ID-jánek lekérdezése */

        exit(1);

  }

 

  mesp.mtip = 1;    /* a kérés típusa mindig 1 */

  mesp.cod_op = atoi(argv[1]);  /* tevékenység kódja parancssorból */

  pid = mesp.pid = getpid();

  printf("a %d kliens elkuldte a kerest\n", mesp.pid);

 

  if (msgsnd(msgid, (struct msgbuf *)&mesp, sizeof(mesp)-sizeof(long), 0) < 0){

        perror("In msgsnd()");  /* tev.kód elküldése a szervernek */

        exit(1);   

  }

 

  if (msgrcv(msgid, (struct msgbuf *)&mesp, sizeof(mesp)-sizeof(long), pid, 0) < 0){

        perror("In msgrcv()");  /* tev.név fogadása a szervertől */

        exit(1);

  }

 

  mesp.mtext[12] = '\0';  /* eredmény előkészítése, kiíratás */

 

  printf("a %d szerver a %d kliensnek %s kerest kuldott\n", mesp.pid, pid, mesp.mtext);

}

 

A szerverfolyamat kap a klienstől egy 1-es típusú üzenetet, majd egy olyan választ készít, amelynek típusa megegyezik a kérést küldő kliens pid-jével. Az alábbi példában a szerver által felkínált szolgáltatások a következők: READ és WRITE. Ezek végrehajtását a szerver csak szimulálja. A választ az mtext mező fogja tartalmazni, amely megmutatja, hogy a szervernek sikerült-e azonosítania a tevékenységet vagy sem.

szerver.c

#include "mes.h"    /* a közös mes állomány */

 

int msgid;    /* üzenetsor azonosítója */

 

void do_it(MESSAGE *mesp) /* tev.kód -> tev.elnevezés */

{

  switch (mesp->cod_op)   /* a kliens által küldött kód */

  {

        case READ:  /* READ = 1 tev. elnevezése */

              strcpy(mesp->mtext, "READ\n");

              break;

        case WRITE: /* WRITE = 2 tev. elnevezése */

              strcpy(mesp->mtext, "WRITE\n");

                    break;

              default:    /* ismeretlen tev.kód */

                    strcpy(mesp->mtext, "Ismeretlen\n");

                    break;

  }

}

 

void main(void)

{

  MESSAGE mesp;     /* üzenet */

  if ((msgid = msgget((key_t) KEY, IPC_CREAT | 0666)) < 0){

        perror("In msgget()");  /* üzenetsor létrehozása */

        exit(1);

  }

 

  while(1)    /* végtelenciklus */

  {

        if (msgrcv(msgid, &mesp, sizeof(mesp)-sizeof(long), 1L, 0) < 0){

              perror("In msgrcv()");  /* tev.kód kiolvasása a sorból */

              exit(1);         

        }

 

        do_it(&mesp);     /* átalakítás */

 

        mesp.mtip = mesp.pid;   /* kliens kódja = üzenet típusa */

        mesp.pid = getpid();

 

        if (msgsnd(msgid, &mesp, sizeof(mesp)-sizeof(long), 0) < 0){

              perror("In msgsnd()");  /* tev. elnevezés küldése */

              exit(1);         

        }

  }

}

 

Makefile(Fedora disztribúció):

 

all: kliens szerver

kliens: kliens.c

  gcc kliens.c -o kl

szerver: szerver.c

  gcc szerver.c -o sz

clean: rm sz kl

.PHONY: all clean

 

A fenti példa egy tesztesetre a következőképpen működik:

$ szerver &
$ kliens 1 & kliens 4

a 995 kliens elkuldte a kerest
a 768 szerver a 995 kliensnek READ kerest kuldott

a 999 kliens elkuldte a kerest
a 768 szerver a 999 kliensnek ismeterlen kerest kuldott

 

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_book.gif  Posix kiegészítés

A posix szabvány szerint az üzenetsorok struktúrája az <mqueue.h> header állományban található.
Típusa : mqd_t

Üzenetsor struktúrája(mq_attr):

Minden üzenetsorhoz van rendelve egy struktúra ami tartalmazza a következő adatokat:

long mq_flags:        Az illető üzenetsor beállításait tartalmazza. Beállítása a mq_setattr() fg-el lehetséges

long mq_maxmsg:      Az üzenetsorban tárolható üzenetek maximális száma. Ennek a mezőnek a beállítása a létrehozás során történik

long mq_msgsize: Az üzenetek mérete

long mq_curmsgs:    Megadja az üzenetsorba található üzenetek számát

long mq_sendwait:  Megadja azon folyamatok számát amelyek üzenetküldésre várakoznak. Amennyiben az értéke nem 0, azt jelenti, hogy az üzenetsor tele van

long mq_recvwait: Megadja azon folyamatok számát amelyek üzenet érkezésére várakoznak. Amennyiben ez a szám nem 0, az üzenetsor üres

Flagek:

            MQ_NONBLOCK: mq_receive() és mq_send() sosem fognak blokkolni

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_book.gif  Műveletek üzenetsorokkal

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Létrehozás (mq_open())

Az mq_open() rendszerfüggvény megnyit vagy létrehoz egy üzenetsort.

Szintaxis:

#include <mqueue.h>

mqd_t mq_open( const char *name, int oflag, [mode_t mode], [mq_attr *attr] )

Megnyitja a name által jelölt üzenetsort a flagek szerint majd visszatéríti az üzenetsor descriptorat

Paraméterek:

name: Az üzenetsor neve( /-el kezdődik).

oflag: Valamelyik az alábbiak közül:
                        O_RDONLY (receive-only)
                        O_WRONLY (send-only)
                        O_RDWR   (send-receive)
                        További flagek:

O_CREAT:    Akkor adjuk meg ha új üzenetsort szeretnénk létrehozni. Amennyiben meg van ez adva, akkor az utolsó két paraméter is    számit. Csak akkor ad hibát ha a name által jelölt üzenetsor létre volt hozva és minden folyamat unlink-elte (mq_unlink()) de nem zárták (mq_close()) be.

O_EXCL:       Hogyha az O_CREAT-al együtt megadjuk akkor létező üzenetsor esetén hibát ad. Semmi értelme magába megadni

O_NONBLOCK:       Nem blokkoló mód. Alapértelmezetten akkor blokkol hogyha az üzenetsor tele van vagy üres.

    mode: A jogosultságok beállítása, pl. : 0666 (Megj.: végrehajtási jogosultság nincs figyelembe véve).

attr:     Ez egy pointer az mq_attr struktúrára amely tartalmazza az üzenetsor tulajdonságait. NULL pointer esetén az alapértelmezett beállításokat veszi alapul:

                Struct mq_attr{

              mq_maxmsg   1024   //ennyi üzenetet tartalmazhat

              mq_msgsize 4096   // egy üzenet mérete

              mq_flags    0      // Posix implementációba nem szükséges megadni

        }

 

Példa:

        char*  name  = argv[1];

              int    flags = O_RDWR | O_CREAT;          //flagek beállítása

              mode_t mode  = 0666;                      //jogok beállítása

 

              struct mq_attr attr;                      //struktura létrehozása és beállítása

              attr.mq_maxmsg  = 10;

              attr.mq_msgsize = sizeof(Msg);

             

      mqd_t qid = mq_open(name, flags, mode, &attr);//Üzenetsor létrehozása

 

Eredmény:
                          Ha sikerült, visszaküldi az üzenetsor deszkriptorát különben -1 es az errno megfelelően be lesz állítva.

escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Bezárás (mq_close())

A mq_close() rendszerfüggvény  bezár egy létező üzenetsort

Szintaxis:

#include <mqueue.h>

Int mq_close( mqd_t mqdes );

Példa:

                mq_close(qid);                            //üzenetsor bezárása

Eredmény:
0 ha sikeresen bezárta különben -1 és az errno megfelelően be lesz állítva

escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Üzenet küldése  (mq_send())

A mq_send()  rendszerfüggvény betesz egy üzenetet egy létező üzenetsorba.

Szintaxis:

#include <mqueue.h>         

int mq_send( mqd_t mqdes,

             const char *msg_ptr,

             size_t msg_len,

             unsigned int msg_prio );

Az mq_send() beteszi a msg_len méretű msq_ptr által mutatott üzenetet msg_prio prioritással az mqdes deszkriptorú üzenetsorba
Az üzenetek rendezve vannak a prioritásuk szerint (0-tól MQ_PRIO_MAX-ig). Ezen belül pedig FIFO sorrendbe.
Ha az üzenetsor megtelt és az O_NONBLOCK nem volt megadva, az mq_send() blokkolja a folyamatot egész addig amíg nem lesz hely.

Példa:

                Msg msg = {rand() % 100, rand() % 100, rand() % 100, 0};

        int prio = rand() % MQ_PRIO_MAX;   

if (mq_send(qid, (char*) &msg, sizeof(Msg), prio) == -1) //üzenet küldése

        {

              perror("Failed to send msg");

        }

Eredmeny:

                        0 ha sikeresen bezárta különben -1 és az errno megfelelően be lesz állítva

escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Üzenet fogadása  (mq_receive())

Az mq_receive() rendszerfüggvény kiolvas egy üzenetet egy létező üzenetsorból.

Szintaxis:

#include <mqueue.h>

int mq_receive( mqd_t mqdes,

                char *msg_ptr,

                size_t msg_len,

                unsigned int *msg_prio );

Az mq_receive() kiolvas egy msg_len méretű üzenetet az mqdes deszkriptorú üzenetsorból az msg_ptr által mutatott helyre. A msg_prio arra az egészre (integer) mutat amelybe a prioritást fogjuk megkapni

mq_receive() abban az esetben blokkol ha:

            -nincs üzenet

            - O_NONBLOCK nem volt bealítva az mq_open() hívásakor.

Ha nem érdekel az üzenet prioritása akkor az msg_prio NULL.

 

Példa:

                Msg msgr = {0,0,0,0};

        if (mq_receive(qid, (char*) &msgr, sizeof(msgr), 0) != -1)  //válasz fogadása

        {

              printf("szum = %d\n", msgr.szum);

        }

        else

        {

                    perror("mq_receive");

                    return(1);

        }

Eredmény:

            Kiolvasott üzenet mérete ha sikerult.

            -1 ha nem sikerült.

escription: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Lecsatlakozás az üzenetsorról  (mq_unlink ())

Az mq_unlink() rendszerfüggvény lecsatlakozik az üzenetsorról

Szintaxis:

#include <mqueue.h>

int mq_unlink( const char *name );

Megjegyzés:
            mq_close()-al ellentétben nem törli az üzenetsort, csak lecsatlakozik róla.

Példa:

mq_unlink(argv[1]);                       //üzenetsor torlése

Eredmény:
            0: sikeres
            -1: sikertelen és errno-t beállítja

escription: Description: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Üzenetsor tulajdonságainak lekérdezése  (mq_getattr())

Az mq_getattr() rendszerfüggvény lekérdézi az üzenetsor tulajdonságait.

Szintaxis:

#include <mqueue.h>

int mq_getattr( mqd_t mqdes,

                struct mq_attr *mqstat );

Lekéri az mqdes deszkriptorú üzenetsor tulajdonságait és elmenti az mqstat pointer által mutatott struktúrába.

Példa:

struct mq_attr temp;   

if (mq_getattr( qid, &temp) == -1 )       //Üzenetsor tulajdonságainak lekérdezése

      perror("getattr:");

else                         

printf("maxmsg = %d\n", temp.mq_maxmsg); 

Eredmény:
            0: sikeres
            -1: sikertelen és errno-t beállítja

escription: Description: Description: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\g_book.gif  Üzenetsor tulajdonságainak beállítása (mq_setattr())

Az mq_setattr() rendszerfüggvény beállítja az üzenetsor tulajdonságait.

Szintaxis:
                       
#include <mqueue.h>

int mq_setattr( mqd_t mqdes,

                const struct mq_attr *mqstat,

                struct mq_attr *omqstat );

Beállítja az mqdes tulajdonságait az mqstat pointer által mutatott struktúra szerint.
Amennyiben az omqstat nem NULL, az omqstat által mutatott struktúra megkapja a régi beállítások.
Az mq_maxmsg és mq_msgsize mezők figyelmen kívül maradnak.          

Példa:

struct mq_attr newattr;

      //adatok beálitása

if (mq_setattr(qid,&newattr,NULL) == -1)

      perror("setattr:")

Eredmény:
            0: sikeres
            -1: sikertelen és errno-t beállítja

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_book.gif  Példa(Letöltés)

Feladat:

Sender.C gombnyomásra küld három számot véletlen prioritással egészen addig amíg be nem olvasunk egy q betűt. Miután elküldte a három számot, megvárja a választ és kiírja.

Receiver.C: kiolvassa az üzenetet(három szám) és visszaküldi az összeget. Ha a kapott üzenet első eleme -1, leáll

Msg.h:

#ifndef MSG_H

#define MSG_H

 

typedef struct

{

  unsigned int x;

  unsigned int y;

  unsigned int z;

  unsigned int szum;

} Msg;

 

#endif

Sender.C:

#include "Msg.h"
#include <mqueue.h>

#include <stdbool.h>

#include <stdio.h>

#include <stdlib.h>   

#include <time.h>     

#include <errno.h>

#include <string.h>

#include <limits.h> // MQ_PRIO_MAX

 

int main(int argc, char** argv)

{

  if (argc != 2)

  {

    printf("Usage:  %s /qname\n", argv[0]);

    return 1;

  }

 

  char*  name  = argv[1];

  int    flags = O_RDWR | O_CREAT;          //flagek beállítása

  mode_t mode  = 0666;                      //jogok beállítása

 

  struct mq_attr attr;                      //struktura létrehozása és beállítása

  attr.mq_flags   = 0;

  attr.mq_maxmsg  = 10;

  attr.mq_msgsize = sizeof(Msg);

  attr.mq_curmsgs = 0;

 

  mqd_t qid = mq_open(name, flags, mode, &attr);//Üzenetsor létrehozása

 

  if (qid == -1)   

              perror("mq_open():");

 

  struct mq_attr temp;   

 

  if (mq_getattr( qid, &temp) == -1 )       //Üzenetsor tulajdonságainak lekérdezése 

        perror("getattr:");

  else                         

        printf("maxmsg = %d\n", temp.mq_maxmsg); 

  srandom(time(0));

  printf("Press enter to send a message...");

  getchar();

  char c;

 

  do

  {

  Msg msg = {random() % 100, random() % 100, random() % 100, 0};

  int prio = random() % MQ_PRIO_MAX;  //Véletlenszerűen generálja az üzenet tartalmát és prioritását

        printf("sending msg = (%03d, %03d, %03d) with priority: %d\n", msg.x, msg.y, msg.z,prio);

        if (mq_send(qid, (char*) &msg, sizeof(Msg), prio) == -1) //üzenet küldése

        {

              perror("Failed to send msg");

        }

  else

  {

        Msg msgr = {0,0,0,0};

        if (mq_receive(qid, (char*) &msgr, sizeof(msgr), 0) != -1)  //válasz fogadása

        {

              printf("szum = %d\n", msgr.szum);

        }

        else

        {

                    perror("mq_receive");

                    return(1);

        }

        printf("Press enter to send another message...");

        c = getchar();

  }

  } while (c != 'q');

 

  Msg msg = {-1,0,0};                       //-1 el kezdődő üzenettel jellezuk, hogy készen vagyunk                 

  if (mq_send(qid, (char*) &msg, sizeof(Msg), 0) == -1)

  {

         perror("Failed to send msg");

  }

 

  mq_close(qid);                            //üzenetsor bezárása         

  mq_unlink(argv[1]);                       //üzenetsor törlése          

  return 0;

}

 

Receiver.C:

 

#include "Msg.h"

#define _XOPEN_SOURCE 600

#include <time.h>

#include <mqueue.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <stdbool.h>

 

int main(int argc, char** argv)

{

  if (argc != 2)

  {

    printf("Usage:  %s /qname\n", argv[0]);

    return 1;

  }

 

  char* name  = argv[1];

  int   flags = O_RDWR;                     //flagek beállítása

 

  mqd_t qid = mq_open(name, flags);         //Üzenetsor megnyitása

 

  if (qid <0)

  {

    perror("Failed to open the message queue");

  }

  bool quit = false;

 

  while (!quit)

  {

    Msg msg = {0,0,0,0};

    unsigned int priority = 0;

             

    if (mq_receive(qid, (char*) &msg, sizeof(msg), &priority) != -1)      //Üzenet fogadása

    {

      if (msg.x != -1)

      {      

        printf("msg = (%03d, %03d, %03d), priority: %d\n", msg.x, msg.y, msg.z, priority);

        msg.szum = msg.x + msg.y + msg.z;

        if (mq_send(qid, (char*) &msg, sizeof(Msg), 0) == -1) //válasz küldése

        {

          perror("Failed to send msg");

        }

      }

      else

            {

        quit=true;

      }

    }

    else

    {

      perror("mq_receive");

      return(1);

    }

  }

  mq_close(qid);                      //üzenetsor bezárása

  return 0;

}

 

Makefile(Fedora disztribúció):

SRC1     = Sender.c

SRC2     = Receiver.c

OBJ1     = $(SRC1:.c=.o)

OBJ2     = $(SRC2:.c=.o)

CFLAGS   = -Wall -pedantic -D_GNU_SOURCE -std=gnu99 -lrt -lmqueue

INCLUDES = -I./

LIBS     = -lrt

LIBPATH  =

DEP_FILE = .depend

SNDR     = sndr

RCVR     = rcvr

 

.PHONY: all clean distclean

 

 

all: depend $(SNDR) $(RCVR)

 

$(SNDR): $(OBJ1)

  @echo Makefile - linking $@

  @$(CC) $(LIBPATH) $(LIBS) $^ -o $@

 

$(RCVR): $(OBJ2)

  @echo Makefile - linking $@

  @$(CC) $(LIBPATH) $(LIBS) $^ -o $@

 

.c.o:

  @echo Makefile - compiling $<

  @$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

 

clean:

  $(RM) $(OBJ1) $(OBJ2)

 

distclean: clean

  $(RM) $(SNDR) $(RCVR)

  $(RM) $(DEP_FILE)

 

depend: $(DEP_FILE)

  @touch $(DEP_FILE)

 

$(DEP_FILE):

  @echo Makefile - building dependencies in: $@

  @$(CC) -E -MM $(CFLAGS) $(INCLUDES) $(SRC1) >> $(DEP_FILE)

  @$(CC) -E -MM $(CFLAGS) $(INCLUDES) $(SRC2) >> $(DEP_FILE)

 

ifeq (,$(findstring clean,$(MAKECMDGOALS)))

ifeq (,$(findstring distclean,$(MAKECMDGOALS)))

-include $(DEP_FILE)

endif

endif

 

Futtatás eredménye:

    Sender.C:

$ ./sndr /uz

maxmsg = 10

Press enter to send a message...

sending msg = (059, 070, 013) with priority: 5595

szum = 142

Press enter to send another message...

sending msg = (070, 034, 064) with priority: 2915

szum = 168

Press enter to send another message...

sending msg = (012, 069, 085) with priority: 8822

szum = 166

Press enter to send another message...

sending msg = (087, 091, 001) with priority: 6281

szum = 179

Press enter to send another message...q

$

    Receiver.C

                $ ./rcvr /uz

msg = (059, 070, 013), priority: 5595

msg = (070, 034, 064), priority: 2915

msg = (012, 069, 085), priority: 8822

msg = (087, 091, 001), priority: 6281

$

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\buttons\n_link_n.gif  Szemaforok (semaphores)

 


Copyright (C) Buzogány László, 2002

escription: Description: Description: Description: Description: Description: C:\Users\ReB\Desktop\Folyamatok\art\simple.gif

About