技術(shù)員聯(lián)盟提供win764位系統(tǒng)下載,win10,win7,xp,裝機(jī)純凈版,64位旗艦版,綠色軟件,免費(fèi)軟件下載基地!

當(dāng)前位置:主頁 > 教程 > 服務(wù)器類 >

linux環(huán)境編程-IPC 之 msg queue

來源:技術(shù)員聯(lián)盟┆發(fā)布時(shí)間:2018-04-24 18:01┆點(diǎn)擊:

在UNIX的SystemV版本,AT&T引進(jìn)了三種新形式的IPC功能(消息隊(duì)列、信號量、以及共享內(nèi)存)。但BSD版本的UNIX使用套接口作為主要的IPC形式。Linux系統(tǒng)同時(shí)支持這兩個(gè)版本。

  系統(tǒng)調(diào)用msgget()

  如果希望創(chuàng)建一個(gè)新的消息隊(duì)列,或者希望存取一個(gè)已經(jīng)存在的消息隊(duì)列,你可以使用系統(tǒng)調(diào)用msgget()。

  系統(tǒng)調(diào)用:msgget();

  原型:int msgget(key_t key, int msgflg);

  返回值:如果成功,返回消息隊(duì)列標(biāo)識符

  如果失敗,則返回-1:errno=EACCESS(權(quán)限不允許)

  EEXIST(隊(duì)列已經(jīng)存在,無法創(chuàng)建)

  EIDRM(隊(duì)列標(biāo)志為刪除)

  ENOENT(隊(duì)列不存在)

  ENOMEM(創(chuàng)建隊(duì)列時(shí)內(nèi)存不夠)

  ENOSPC(超出最大隊(duì)列限制)

  系統(tǒng)調(diào)用msgget()中的第一個(gè)參數(shù)是關(guān)鍵字值(通常是由ftok() 返回的)。然后此關(guān)鍵字值將會(huì)和其他已經(jīng)存在于系統(tǒng)內(nèi)核中的關(guān)鍵字值比較。這時(shí),打開和存取操作是和參數(shù)msgflg中的內(nèi)容相關(guān)的。

  IPC_CREAT如果內(nèi)核中沒有此隊(duì)列,則創(chuàng)建它。

  IPC_EXCL當(dāng)和IPC_CREAT一起使用時(shí),如果隊(duì)列已經(jīng)存在,則失敗。

  如果單獨(dú)使用IPC_CREAT,則msgget()要么返回一個(gè)新創(chuàng)建的消息隊(duì)列的標(biāo)識符,要么返回具有相同關(guān)鍵字值的隊(duì)列的標(biāo)識符。如果IPC_EXCL和IPC_CREAT一起使用,則msgget()要么創(chuàng)建一個(gè)新的消息隊(duì)列,要么如果隊(duì)列已經(jīng)存在則返回一個(gè)失敗值-1。IPC_EXCL單獨(dú)使用是沒有用處的。

  下面看一個(gè)打開和創(chuàng)建一個(gè)消息隊(duì)列的例子:

  int open_queue(key_t keyval)

  {

  intqid;

  if((qid=msgget (keyval, IPC_CREAT|0660))==-1)

  {

  return(-1);

  }

  return(qid);

  }

  系統(tǒng)調(diào)用msgsnd()

  一旦我們得到了隊(duì)列標(biāo)識符,我們就可以在隊(duì)列上執(zhí)行我們希望的操作了。如果想要往隊(duì)列中發(fā)送一條消息,你可以使用系統(tǒng)調(diào)用msgsnd():

  系統(tǒng)調(diào)用:msgsnd();

  原型:int msgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg);

  返回值:如果成功,0。

  如果失敗,-1:errno=EAGAIN(隊(duì)列已滿,并且使用了IPC_NOWAIT)

  EACCES(沒有寫的權(quán)限)

  EFAULT(msgp地址無效)

  EIDRM(消息隊(duì)列已經(jīng)刪除)

  EINTR(當(dāng)?shù)却龑懖僮鲿r(shí),收到一個(gè)信號)

  EINVAL(無效的消息隊(duì)列標(biāo)識符,非正數(shù)的消息類型,或

  者無效的消息長度)

  ENOMEM(沒有足夠的內(nèi)存復(fù)制消息緩沖區(qū))

  系統(tǒng)調(diào)用msgsnd()的第一個(gè)參數(shù)是消息隊(duì)列標(biāo)識符,它是由系統(tǒng)調(diào)用msgget返回的。第二個(gè)參數(shù)是msgp,是指向消息緩沖區(qū)的指針。參數(shù)msgsz中包含的是消息的字節(jié)大小,但不包括消息類型的長度(4個(gè)字節(jié))。

  參數(shù)msgflg可以設(shè)置為0(此時(shí)為忽略此參數(shù)),或者使用IPC_NOWAIT。

  如果消息隊(duì)列已滿,那么此消息則不會(huì)寫入到消息隊(duì)列中,控制將返回到調(diào)用進(jìn)程中。如果沒有指明,調(diào)用進(jìn)程將會(huì)掛起,直到消息可以寫入到隊(duì)列中。

  下面是一個(gè)發(fā)送消息的程序:

  int send_message(int qid, struct mymsgbuf *qbuf)

  {

  intresult,length;

  /*The length is essentially the size of the structure minus sizeof(mtype)*/

  length=sizeof(structmymsgbuf)-sizeof(long);

  if((result = msgsnd (qid, qbuf, length, 0))==-1)

  {

  return(-1);

  }

  return(result);

  }

  系統(tǒng)調(diào)用:msgrcv();

  原型:int msgrcv(intmsqid,structmsgbuf*msgp,intmsgsz,longmtype,intmsgflg);

  返回值:如果成功,則返回復(fù)制到消息緩沖區(qū)的字節(jié)數(shù)。

  如果失敗,則返回-1:errno=E2BIG(消息的長度大于msgsz,沒有MSG_NOERROR)

  EACCES(沒有讀的權(quán)限)

  EFAULT(msgp指向的地址是無效的)

  EIDRM(隊(duì)列已經(jīng)被刪除)

  EINTR(被信號中斷)

  EINVAL(msgqid無效,或者msgsz小于0)

  ENOMSG(使用IPC_NOWAIT,同時(shí)隊(duì)列中的消息無法滿足要求)

  第一個(gè)參數(shù)用來指定將要讀取消息的隊(duì)列 。第二個(gè)參數(shù)代表要存儲消息的消息緩沖區(qū) 的地址。第三個(gè)參數(shù)是消息緩沖區(qū)的長度,不包括mtype的長度,它可以按照如下的方法計(jì)算:

  msgsz=sizeof(struct mymsgbuf)-sizeof(long);

  第四個(gè)參數(shù)是要從消息隊(duì)列中讀取的消息的類型。如果此參數(shù)的值為0,那么隊(duì)列中最長時(shí)間的一條消息將返回,而不論其類型是什么。

  如果調(diào)用中使用了IPC_NOWAIT作為標(biāo)志,那么當(dāng)沒有數(shù)據(jù)可以使用時(shí),調(diào)用將把ENOMSG返回到調(diào)用進(jìn)程中。否則,調(diào)用進(jìn)程將會(huì)掛起,直到隊(duì)列中的一條消息滿足msgrcv()的參數(shù)要求。如果當(dāng)客戶端等待一條消息的時(shí)候隊(duì)列為空,將會(huì)返回EIDRM。如果進(jìn)程在等待消息的過程中捕捉到一個(gè)信號,則返回EINTR。

  下面就是一個(gè)從隊(duì)列中讀取消息的程序:

  int read_message(int qid,long type,struct mymsgbuf*qbuf)

  {

  intresult,length;

  /*The length is essentially the size of the structure minus sizeof(mtype)*/

  length=sizeof(struct mymsgbuf)-sizeof(long);

  if((result=msgrcv(qid,qbuf,length,type,0))==-1)

  {

  return(-1);

  }

  return(result);

  }

  在成功地讀取了一條消息以后,隊(duì)列中的這條消息的入口將被刪除