MyException - 我的异常网
当前位置:我的异常网» 操作系统 » XSI IPC通讯之消息队列

XSI IPC通讯之消息队列

www.MyException.Cn  网友分享于:2018-04-18  浏览:0次
XSI IPC通信之消息队列
    消息队列是消息的链接表,存储在内核中,由消息队列标识符(或称为队列ID)标识。
    下表列出了影响消息队列的系统限制。其中“导出的”表示这种限制来源于其他限制。比如 Linux 系统中的最大消息数是根据最大队列数和队列中所允许的最大数据量来决定的,最大队列数又受 RAM 数量多少的影响,队列的最大字节数限制进一步限制了队列中将要存储的消息的最大长度。

    每个队列都关联有一个 msqid_ds 结构,它定义了队列的当前状态,至少支持下面这些字段,其中的 ipc_perm 结构见XSI IPC 相似特征介绍一节:
struct msqid_ds{
    struct ipc_perm    msg_perm;
    msgqnum_t          msg_qnum;        // # of messages on queue
    msglen_t           msg_qbytes;      // max # of bytes on queue
    pid_t              msg_lspid;       // pid of last msgsnd()
    pid_t              msg_lrpid;       // pid of last msgrcv()
    time_t             msg_stime;       // last-msgsnd() time
    time_t             msg_rtime;       // last-msgrcv() time
    time_t             msg_ctime;       // last-change time
    /* ... */
};

    msgget 函数用于创建一个新队列或打开一个现有队列。msgsnd 将新消息添加到队列尾端。msgrcv 用于从队列中取消息,但不一定是以先进先出次序取,也可以按消息的类型字段来取。msgctl 可对队列执行多种操作,它和后面章节中要介绍的另外两个与信号量及共享存储有关的函数 semctl 和 shmctl 都是 XSI IPC 的类似于 ioctl 的函数(亦即垃圾桶函数)。
#include <sys/msg.h>
int msgget(key_t key, int flag);
                      /* 返回值:若成功,返回消息队列 ID;否则,返回 -1 */
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
                      /* 返回值:若成功,返回 0;否则,返回 -1 */
ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
                      /* 返回值:若成功,返回消息数据部分的长度;否则,返回 -1 */
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
                      /* 返回值:若成功,返回 0;否则,返回 -1 */

    在XSI IPC 相似特征介绍一节中说明了将 key 变换成一个标识符的规则。
    使用 msgget 函数在创建新队列时,会初始化 msqid_ds 结构的下列成员。
    * ipc_perm 结构按XSI IPC 相似特征介绍一节中的所述进行初始化,其中的 mode 成员按 flag 中的相应权限位设置。
    * msg_qnum、msg_lspid、msg_lrpid、msg_stime 和 msg_rtime 都设置为 0。
    * msg_ctime 设置为当前时间。
    * msg_qbytes 设置为系统限制值。
    msgget 执行成功后返回的非负队列 ID 就可用于其他 3 个消息队列函数。
    msqsnd 函数将消息添加到队列尾端。每个消息包含一个正的长整型的字段、一个非负的长度 nbytes 以及对应于长度的实际数据字节数。msgsnd 中的 ptr 参数指向一个长整型数,它包含了正的整型消息类型,其后紧接着的是消息数据(若 nbytes 是 0 则无数据)。比如发送的最长消息是 512 字节,则可定义类似下列结构:
        struct mymesg{
            long mtype;         // positive message type
            char mtext[512];    // message data, of length nbytes
        };
    此时参数 ptr 就是一个指向 mymesg 结构的指针。接收者可以使用消息类型以非先进先出的次序取消息。要注意的是,有些平台同时支持 32 位和 64 位环境,这会影响到长整型和指针的大小。如果一个 32 位应用程序要经由管道或套接字与一个 64 位应用程序交换此结构,就会出问题。因为长整型的大小在 32 位环境中是 4 字节,而 64 位环境中则是 8 字节。在这种情况下,64 位应用程序的 mtype 字段的一部分会被 32 位应用程序视为 mtext 字段的组成部分,而 32 位应用程序的 mtext 字段的前 4 个字节会被 64 位应用程序解释为 mtype 字段的组成部分。即使对 IPC 系统调用的 32 位和 64 位版本具有不同的入口点,也存在潜在问题:当 64 位应用程序向 32 位应用程序发送消息时,如果它在 8 字节类型字段中设置的值大于 32 位应用程序中 4 字节类型字段可表示的值,那么 32 位应用程序在其 mtype 字段中得到的将是一个截短了的类型值。
    参数 flag 的值可以指定为 IPC_NOWAIT,这类似于文件 I/O 的非阻塞标志。若消息队列已满(或是队列中的消息总数或者队列中的字节总数等于了系统限制值),则指定 IPC_NOWAIT 可使 msgsnd 立即出错返回 EAGAIN,否则进程会一直阻塞到:有空间可以容纳要发送的消息;或者从系统中删除了此队列(此时会返回 EIDRM 错误);或者捕捉到一个信号,并从信号处理程序返回(此时会返回 EINTR 错误)。
    msgsnd 成功返回时,消息队列相关的 msqid_ds 结构也会随之更新。
    和 msgsnd 一样,msgrcv 中的 ptr 参数指向一个长整型数(其中存储的是返回的消息类型),其后跟随的是存储实际消息数据的缓冲区。nbytes 参数指定数据缓冲区的长度。若返回的消息长度大于 nbytes,而且在 flag 中设置了 MSG_NOERROR 位,则该消息会被自动截断,并丢弃多余的部分。如果消息太长时没设置此标志,则出错返回 E2BIG,但消息仍留在队列中。
    参数 type 可通过设置为下列值来指定想要哪一种消息。
    * 等于 0:返回队列中的第一个消息。
    * 大于 0:返回队列中消息类型为 type 的第一个消息。
    * 小于 0:返回队列中消息类型值不大于 type 绝对值的消息。如果这种消息有若干个,则取类型值最小的消息。
    type 值非 0 可用于以非先进先出次序读消息,例如可以用来代表优先级权值,或是表示客户进程的进程 ID 等。
    flag 参数也可指定为 IPC_NOWAIT 标志,以使操作不阻塞。这样,如果没有所指定类型的消息可用,则立即返回 -1,并将 errno 设置为 ENOMSG。没指定此标志时的阻塞情况同 msgsnd。
    msgrcv 执行成功时,msqid_ds 结构同样也会更新。
    msgctl 函数中的 cmd 参数指定了对 msqid 参数表示的队列要执行的下列命令之一。
    * IPC_STAT:取此队列的 msqid_ds 结构,并将其存放在 buf 指向的结构中。
    * IPC_SET:将字段 msg_perm.uid、msg_perm.gid、msg_perm.mode 和 msg_qbytes 从 buf 指向的结构复制到此队列关联的 msqid_ds 结构中。此命令只能由下列两种进程执行:一种是其有效用户 ID 等于 msg_perm.cuid 或 msg_perm.uid,另一种是具有超级用户特权的进程。只有超级用户才能增加 msg_qbytes 的值。
    * IPC_RMID:从系统中删除该消息队列以及仍在其中的所有数据。这种删除立即生效,仍在使用这个队列的其他进程在下一次试图操作此队列时将得到 EIDRM 错误。该命令也只能由上面提及的两种进程执行。注意,由于消息队列没有像文件一样维护引用计数器,所以继续操作被删除的队列的进程会出错返回,而不是像文件操作中需要等最后一个进程关闭了文件描述符后才能删除文件中的内容。后面要介绍的信号量机制也以这种方式处理其删除。
    这 3 条命令也可用于后文中要介绍的信号量和共享存储。
    最后要提醒的一点是,由于这种消息队列现在在速度方面已经和其他的 IPC 方式没有什么差别了,考虑到使用消息队列时遇到的问题,在新的应用程序中已经不再推荐使用了。

文章评论

团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
程序员和编码员之间的区别
程序员和编码员之间的区别
我是如何打败拖延症的
我是如何打败拖延症的
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
为什么程序员都是夜猫子
为什么程序员都是夜猫子
 程序员的样子
程序员的样子
中美印日四国程序员比较
中美印日四国程序员比较
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
每天工作4小时的程序员
每天工作4小时的程序员
旅行,写作,编程
旅行,写作,编程
如何成为一名黑客
如何成为一名黑客
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
那些争议最大的编程观点
那些争议最大的编程观点
代码女神横空出世
代码女神横空出世
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
Java程序员必看电影
Java程序员必看电影
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
程序员的鄙视链
程序员的鄙视链
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
总结2014中国互联网十大段子
总结2014中国互联网十大段子
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
鲜为人知的编程真相
鲜为人知的编程真相
程序员应该关注的一些事儿
程序员应该关注的一些事儿
一个程序员的时间管理
一个程序员的时间管理
我的丈夫是个程序员
我的丈夫是个程序员
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
编程语言是女人
编程语言是女人
程序员都该阅读的书
程序员都该阅读的书
漫画:程序员的工作
漫画:程序员的工作
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有