linuxIPC——消息队列

<h1 class="title_txt">
<span style="font-size: medium;"><cite class="fav_csdnstylebykimi"> </cite>
</span>

</h1>
<div class="blogstory">
<p><span style="font-size: medium;">1. 消息队列</span>
</p>
<p><span style="font-size: medium;">1.1消息队列</span>
</p>
<p><span style="font-size: medium;">消息队列是消息的链接表,存放着内核中由消息队列标识符标识。消息队列简称队列(queue),其标识符为队列ID(queue ID)。</span>
</p>
<p><span style="font-size: medium;">每个队列都有一个msqid_ds结构与其相关联:</span>
</p>
<p><span style="font-size: medium;">struct msqid_ds{</span>
</p>
<p><span style="font-size: medium;">struct ipc_perm msg_perm; //</span>
</p>
<p><span style="font-size: medium;">msgqnum_t msg_qnum; // # of messages on queue</span>
</p>
<p><span style="font-size: medium;">msglen_t msg_qbytes; // max # of bytes on queue</span>
</p>
<p><span style="font-size: medium;">pid_t msg_lspid; // pid of last msgsnd</span>
</p>
<p><span style="font-size: medium;">pid_t msg_lrpid; // pid of last msgrcv</span>
</p>
<p><span style="font-size: medium;">time_t msg_rtime; // last-msgsnd time</span>
</p>
<p><span style="font-size: medium;">time_t msg_rtime; // last-msgrcv time</span>
</p>
<p><span style="font-size: medium;">time_t msg_ctime; // last-change time</span>
</p>
<p><span style="font-size: medium;">.</span>
</p>
<p><span style="font-size: medium;">.</span>
</p>
<p><span style="font-size: medium;">.</span>
</p>
<p><span style="font-size: medium;">}</span>
</p>
<p><span style="font-size: medium;">msgget用于创建一个新队列或打开一个现存的队列。msgsnd将新消息添加到队列尾端。每个消息包含一个正长整型类型字段,一个非负长度以及
实际数据字节(对应于长度),所以这些都在将消息添加到队列时,传送给msgsnd。Msgrcv用于从队列中取消息。我们并不一定要以先进先出次序取消
息,也可以按消息的类型字段取消息。</span>
</p>
<p><span style="font-size: medium;">调用的第一个函数通常是msgget,其功能是打开一个现存队列或创建一个新队列。</span>
</p>
<p><span style="font-size: medium;">#include &lt;sys/msg.h&gt;</span>
</p>
<p><span style="font-size: medium;">int msgget(key_t key, int flag);</span>
</p>
<p><span style="font-size: medium;">若执行成功,msgget返回非负队列ID,此值就可被用于其它三个消息队列函数。</span>
</p>
<p><span style="font-size: medium;">函数msgctl对队列执行多种操作。它和另外两个与信号量和共享内存有关的函数(semctl和shmctl)是XSI IPC的类似于ioctl的函数。</span>
</p>
<p><span style="font-size: medium;">#include &lt;sys/msg.h&gt;</span>
</p>
<p><span style="font-size: medium;">int msgctl (int msqid, int cmd, struct msqid_ds *buf);</span>
</p>
<p><span style="font-size: medium;">参数cmd说明对由msqid指定的队列要执行的命令:</span>
</p>
<p><span style="font-size: medium;">IPC_STAT 取此队列的msqid_ds结构,并将它存放着buf指向的结构中。</span>
</p>
<p><span style="font-size: medium;">IPC_SET
按由buf指向结构中的值,设置与此队列相关结构中的下列四个字段:msg_perm.uid、msg_perm.gid、msg_perm.mode和
msg_qbtes。此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid;另一种是具有超级
用户特权的进程。只有超级用户才能增加msg_gbytes的值。</span>
</p>
<p><span style="font-size: medium;">IPC_RMID
从系统中删除该消息队列以及仍在该队列中的所有数据。这种删除立即生效。仍在使用这一消息队列的其它进程在它们下一次试图对此队列进行操作时,将出错返回
EIDRM。此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid;另一种是具有超级用户特权
的进程。只有超级用户才能增加msg_gbytes的值。</span>
</p>
<p><span style="font-size: medium;">调用msgsnd将数据放到消息队列中。</span>
</p>
<p><span style="font-size: medium;">#include &lt;sys/msg.h&gt;</span>
</p>
<p><span style="font-size: medium;">int msgsnd (int msqid, const void *ptr, size_t nbytes, int flag);</span>
</p>
<p><span style="font-size: medium;">我们知道每个消息由三部分组成:正常正行字段、非负长度(nbytes)、以及实际数据字节(对应于长度)。消息总是放在队列尾端。</span>
</p>
<p><span style="font-size: medium;">参数ptr指向一个长整形数,它包含了正的整型消息类型,在其后紧跟着消息数据。(若nbytes是0,则无消息数据)。若发送的最长消息是256字节,则可以定义下列结构:</span>
</p>
<p><span style="font-size: medium;">struct mymsg{</span>
</p>
<p><span style="font-size: medium;"> long type; //消息类型</span>
</p>
<p><span style="font-size: medium;"> char data[256]; //消息数据和长度</span>
</p>
<p><span style="font-size: medium;">};</span>
</p>
<p><span style="font-size: medium;">于是,ptr就是一个指向mymsg结构的指针。</span>
</p>
<p><span style="font-size: medium;">参数flag的值可以指定为IPC_NOWAIT。这类似于文件I/O的非阻塞I/O标志。若消息队列已满(或是队列中的消息总数等于系统的限制,
或是队列中的字节总数等于系统的限制),则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。如果没有指定IPC_NOWAIT,则进
程阻塞直到下述情况出现为止:有空间可以容纳要发送的消息;从系统中删除了此队列(EIDRM);或是捕捉到一个信号,并从信号处理程序返回
(EINTR)。</span>
</p>
<p><span style="font-size: medium;">注意,删除队列使得仍在使用这一消息队列的其它进程在它们下一次试图对此队列进行操作时,将出错返回EIDRM。信号机制也以同样的方式处理其删除。相反,删除一个文件时,要等到使用该文件的最后一个进程关闭了它的文件描述符后,才能删除该文件的内容。</span>
</p>
<p><span style="font-size: medium;">当msgsnd成功返回,与消息队列相关的msqid_ds结构得到更新,以表明发出该调用的进程ID(msg_lspid)、进行内核调用的时间(msg_stime),并指示队列中增加了一条消息(msg-qnum)。</span>
</p>
<p><span style="font-size: medium;">函数msgrcv从队列中取消息:</span>
</p>
<p><span style="font-size: medium;">ssize_t msgrcv(int msqid, viod *ptr, size_t nbytes, long type, int flag);</span>
</p>
<p><span style="font-size: medium;">如同msgsnd中一样,ptr参数指向一个长整型数(返回的消息类型存放在其中),跟随其后的是存放实际消息数据的缓冲区。Nbytes说明数据
缓冲区的长度。若返回的消息大于nbytes,而且在flag中设置了MSG_NOERROR,则该消息被截断。如果没有设置这一标识,而且消息又太长,
则出错返回E2BIG(消息仍留在队列中)。</span>
</p>
<p><span style="font-size: medium;">参数type使我们可以指定想要哪种消息:</span>
</p>
<p><span style="font-size: medium;">type == 0 返回队列中的第一个消息</span>
</p>
<p><span style="font-size: medium;">type &gt; 0 返回队列中消息类型为type的第一个消息</span>
</p>
<p><span style="font-size: medium;">type &lt; 0 返回队列中消息类型小于或等于type绝对值的消息,如果这种消息有若干个,则取类型最小的消息。</span>
</p>
<p><span style="font-size: medium;">参数type非0用于以非先进先出的次序读消息。</span>
</p>
<p><span style="font-size: medium;">参数flag可以指定IPC_NOWAIT,使操作不阻塞。这使得如果没有指定类型的消息,则msgrcv返回-1;errno设置为
ENOMSG。如果没有指定IPC_NOWAIT,则进程阻塞直至如下情况出现才终止:有了指定类型的消息,从系统中删除此队列(出错返回-1则
errno设置为EIDRM),或者捕捉一个信号从信号处理程序返回(msgrcg返回-1,则errno设置为EINTR)。</span>
</p>
<p><span style="font-size: medium;">当msgrcv成功执行时,内核更新与该消息队列相关联的msqid_ds结构,以指示调用者的进程ID(msg_lrpid)和调用时间(msg_rtime),并将队列中的消息数(msg_qnum)减一。</span>
</p>
<p><span style="font-size: medium;">1.2. 实例</span>
</p>
<p><span style="font-size: medium;">下面是两个小程序:msgrcv.c用于接收消息,msgsnd用于发送消息。这两个都可以创建消息队列,但只有接收者在收到最后一个消息之后可以删除这个消息队列。执行结果如下:</span>
</p>
<p><span style="font-size: medium;">#./msgsnd</span>
</p>
<p><span style="font-size: medium;">Please input data: hello</span>
</p>
<p><span style="font-size: medium;">Please input data: how are you</span>
</p>
<p><span style="font-size: medium;">Please input data: end</span>
</p>
<p><span style="font-size: medium;">#./msgrcv</span>
</p>
<p><span style="font-size: medium;">receive data: hello</span>
</p>
<p><span style="font-size: medium;">receive data: how are you</span>
</p>
<p><span style="font-size: medium;">receive data: end</span>
</p>
<p><span style="font-size: medium;">#</span>
</p>
<p><span style="font-size: medium;">源程序如下:</span>
</p>
<ol class="dp-c">
<li class="alt">
<span style="font-size: medium;"><span class="preprocessor">#include&lt;stdlib.h&gt;</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="preprocessor">#include&lt;stdio.h&gt;</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="preprocessor">#include&lt;string.h&gt;</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="preprocessor">#include&lt;unistd.h&gt;</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="preprocessor">#include&lt;errno.h&gt;</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="preprocessor">#include&lt;sys/types.h&gt;</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="preprocessor">#include&lt;sys/ipc.h&gt;</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="preprocessor">#include&lt;sys/msg.h&gt;</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"></span>
</li>
<li>
<span style="font-size: medium;"><span class="preprocessor">#defineBUF_SIZE32</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="preprocessor">#defineMY_PROC_RCV_ID4</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="preprocessor">#defineMY_PROC_SND_TYPE2</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="preprocessor">#defineMY_PROC_PATH"/user/local/wzhwho"</span>
</span>
</li>
<li>
<span style="font-size: medium;"></span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">struct</span>
mymsgst{</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">long</span>
<span class="keyword">int</span>
type;</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">char</span>
data[BUF_SIZE];</span>
</li>
<li>
<span style="font-size: medium;"></span>
</li>
<li class="alt">
<span style="font-size: medium;">};</span>
</li>
<li>
<span style="font-size: medium;"></span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="comment">/*******************************************************************************</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="comment">*</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="comment">*消息机制实例(接收者的程序,msgrcv.c)</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="comment">*</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="comment">*******************************************************************************/</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">int</span>
main()</span>
</li>
<li class="alt">
<span style="font-size: medium;">{</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">int</span>
msgid;</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">int</span>
running=1;</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">struct</span>
mymsgstmy_msg;</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">long</span>
<span class="keyword">int</span>
rcv_num=0;</span>
</li>
<li>
<span style="font-size: medium;">key_tmy_msg_kt;</span>
</li>
<li class="alt">
<span style="font-size: medium;"></span>
</li>
<li>
<span style="font-size: medium;"><span class="comment">/*获取消息队列的ID*/</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;">my_msg_kt=ftok(MY_PROC_PATH,MY_PROC_RCV_ID);</span>
</li>
<li>
<span style="font-size: medium;">msgid=msgget(my_msg_kt,0666|IPC_CREAT);</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">if</span>
(msgid&lt;0)</span>
</li>
<li>
<span style="font-size: medium;">{</span>
</li>
<li class="alt">
<span style="font-size: medium;">printf(<span class="string">"msggetfailedwitherror:%s,ERRNO=0x%x/n"</span>
,strerrno(errno),errno);</span>
</li>
<li>
<span style="font-size: medium;">exit(EXIT_FAILURE);</span>
</li>
<li class="alt">
<span style="font-size: medium;">}</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">while</span>
(running)</span>
</li>
<li class="alt">
<span style="font-size: medium;">{</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">if</span>
(msgrcv(msgid,(<span class="keyword">void</span>
*)&amp;my_msg,BUF_SIZE,rcv_num,0)==-1)</span>
</li>
<li class="alt">
<span style="font-size: medium;">{</span>
</li>
<li>
<span style="font-size: medium;">printf(<span class="string">"msgrcvfailedwitherror:%s,ERRNO=0x%x/n"</span>
,strerrno(errno),errno);</span>
</li>
<li class="alt">
<span style="font-size: medium;">exit(EXIT_FAILURE);</span>
</li>
<li>
<span style="font-size: medium;">}</span>
</li>
<li class="alt">
<span style="font-size: medium;">printf(<span class="string">"receivedata:%s/n"</span>
,my_msg.data);</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">if</span>
(stncmp(my_msg.data,<span class="string">"end"</span>
,3)==0)</span>
</li>
<li class="alt">
<span style="font-size: medium;">{</span>
</li>
<li>
<span style="font-size: medium;">running=0;</span>
</li>
<li class="alt">
<span style="font-size: medium;">}</span>
</li>
<li>
<span style="font-size: medium;">}</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">if</span>
(msgctl(msgid,IPC_RMID,0)==-1)</span>
</li>
<li>
<span style="font-size: medium;">{</span>
</li>
<li class="alt">
<span style="font-size: medium;">printf(<span class="string">"msgctlfailedwitherror:%s,ERRNO=0x%x/n"</span>
,strerrno(errno),errno);</span>
</li>
<li>
<span style="font-size: medium;">exit(EXIT_FAILURE);</span>
</li>
<li class="alt">
<span style="font-size: medium;">}</span>
</li>
<li>
<span style="font-size: medium;">exit(EXIT_SUCCESS);</span>
</li>
<li class="alt">
<span style="font-size: medium;">}</span>
</li>
<li>
<span style="font-size: medium;"></span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="comment">/*******************************************************************************</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="comment">*</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="comment">*消息机制实例(发送者的程序,msgsnd.c)</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="comment">*</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="comment">*******************************************************************************/</span>
</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">int</span>
main()</span>
</li>
<li class="alt">
<span style="font-size: medium;">{</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">int</span>
msgid;</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">int</span>
running=1;</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">struct</span>
mymsgstmy_msg;</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">char</span>
buffer[BUF_SIZE]={0};</span>
</li>
<li>
<span style="font-size: medium;">key_tmy_msg_kt;</span>
</li>
<li class="alt">
<span style="font-size: medium;"></span>
</li>
<li>
<span style="font-size: medium;"><span class="comment">/*设置消息类型*/</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;">my_msg.type=MY_PROC_SND_TYPE;</span>
</li>
<li>
<span style="font-size: medium;"><span class="comment">/*获取消息队列的ID*/</span>
</span>
</li>
<li class="alt">
<span style="font-size: medium;">my_msg_kt=ftok(MY_PROC_PATH,MY_PROC_RCV_ID);</span>
</li>
<li>
<span style="font-size: medium;">msgid=msgget(my_msg_kt,0666|IPC_CREAT);</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">if</span>
(msgid&lt;0)</span>
</li>
<li>
<span style="font-size: medium;">{</span>
</li>
<li class="alt">
<span style="font-size: medium;">printf(<span class="string">"msggetfailedwitherror:%s,ERRNO=0x%x/n"</span>
,strerrno(errno),errno);</span>
</li>
<li>
<span style="font-size: medium;">exit(EXIT_FAILURE);</span>
</li>
<li class="alt">
<span style="font-size: medium;">}</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">while</span>
(running)</span>
</li>
<li class="alt">
<span style="font-size: medium;">{</span>
</li>
<li>
<span style="font-size: medium;">printf(<span class="string">"Pleaseinputdata:"</span>
);</span>
</li>
<li class="alt">
<span style="font-size: medium;">fgets(buffer,BUF_SIZE,stdin);</span>
</li>
<li>
<span style="font-size: medium;">strncpy(my_msg.data,buffer,<span class="keyword">sizeof</span>
(my_msg.data));</span>
</li>
<li class="alt">
<span style="font-size: medium;">my_msg.data[BUF_SIZE]=<span class="string">'/0'</span>
;</span>
</li>
<li>
<span style="font-size: medium;"><span class="keyword">if</span>
(msgsnd(msgid,(<span class="keyword">void</span>
*)&amp;my_msg,BUF_SIZE,0)==-1)</span>
</li>
<li class="alt">
<span style="font-size: medium;">{</span>
</li>
<li>
<span style="font-size: medium;">printf(<span class="string">"msgsndfailedwitherror:%s,ERRNO=0x%x/n"</span>
,strerrno(errno),errno);</span>
</li>
<li class="alt">
<span style="font-size: medium;">exit(EXIT_FAILURE);</span>
</li>
<li>
<span style="font-size: medium;">}</span>
</li>
<li class="alt">
<span style="font-size: medium;"><span class="keyword">if</span>
(stncmp(my_msg.data,<span class="string">"end"</span>
,3)==0)</span>
</li>
<li>
<span style="font-size: medium;">{</span>
</li>
<li class="alt">
<span style="font-size: medium;">running=0;</span>
</li>
<li>
<span style="font-size: medium;">}</span>
</li>
<li class="alt">
<span style="font-size: medium;">}</span>
</li>
<li>
<span style="font-size: medium;">exit(EXIT_SUCCESS);</span>
</li>
<li class="alt">
<span style="font-size: medium;">} <br></span>
</li>
</ol>
</div>

你可能感兴趣的:(linux)