内核中的System V消息队列用一个消息队列标识符表示,每个消息队列维护一个结构体(如图)
消息队列可以类似画成一个链 表。
每个消息由类型,长度和数据组成。
msgget函数通过key(由ftok函数或者IPC_PRIVATE创建)创建一个新的消息队列。
打开消息队列后,msgsnd向消息队列发送数据。
msqid是消息队列表示符,ptr是一个结构指针,指向消息。
也可以是自定义的消息结构。Flag可以设置消息队列为非阻塞。
使用msgrcv函数可以从某个消息队列中读出一个消息。
msqid消息队列表示符,ptr接收缓冲区,length数据部分长度,type读出消息的类型,flag可以设置非阻塞读。
type=0,返回队列第一个消息,type>0,返回类型值为type的第一个消息,type<0返回类型值小于等于type参数的绝对值消息中类型最小的第一个消息。
msgctl控制消息队列,可以删除指定的消息队列,或者设置消息队列的属性。
例1:使用两个消息队列实现两个进程的通信。
一个消息队列用来从A发给B,B读取A。
另一个消息队列用来B发给A,A读取B。
例2:可以使用一个消息队列实现两个进程的通信。
A发给B类型为n的消息,B读取类型为n的消息。
B发送给A类型为m的消息,A读取类型为m的消息。
例3:使用一个消息队列用于一个服务器和多个客户端通信
约定类型为1的消息是从客户到服务器的,其他所有消息等于客户进程的类型。
客户向服务器的消息队列写自己的pid和路径名,类型为1。
服务器接受类型为1的消息,从中读出Pid和路径名,然后把文件内容发送给消息队列,类型为pid。
例4:每个客户一个消息队列和服务器通信
每个客户端使用一个队列,客户给服务器消息队列发送消息,把自己的队列标识符顺便发过去。
服务器收到消息,使用fork创建一个子进程,在子进程中读取文件,把文件内容发送给客户端的消息队列。
(1)需要给SIGCHLD建立信号处理程序。fork出来的子进程不及时回收会成为僵尸进程。进程结束后会向父进程发送SIGCHLD信号,需要手动处理。
(2)fopen需要放在子进程中,这样打开文件阻塞的话,不会阻塞服务器的正常运行。
(3)这样设计的潜在问题是如果某个客户中途死亡,它的私用队列可能永远残留消息。
System V消息队列上使用select和poll
如果想要同时处理网络连接和IPC连接的服务器,会出现问题。IPC描述符和文件描述符不同。
(1)可以让服务器创建一个管道,然后fork一个子进程阻塞在msgrcv调用中。
当有消息时,子进程从队列中读出消息,然后把消息写入管道,让select监听管道描述符的读端(fd[0])。
这样消息被处理的三次。
(2)父进程可以创建一个在它自身和子进程之间分享的共享内存区,然后把把管道用作父子进程间的一种标志。
(这个地方没看懂。)
消息队列限制: