Chinaunix首页 | 论坛 | 博客
  • 博客访问: 534835
  • 博文数量: 86
  • 博客积分: 1076
  • 博客等级: 准尉
  • 技术积分: 1018
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-02 19:15
文章分类

全部博文(86)

文章存档

2013年(15)

2012年(69)

2011年(2)

分类: LINUX

2012-03-31 14:35:00

     消息队列简称队列,其标示符为队列ID。可以通过命令ipcs -q查看当前系统的消息队列。

  1. root@jgf:~/linux-2.6.32.2# ipcs -q
  2. ------ Message Queues --------
  3. key msqid owner perms used-bytes messages
  4. root@jgf:~/linux-2.6.32.2#

     消息队列就是一个消息的链表,可以把消息对列看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向其中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。
     消息队列的实现包括创建或打开消息队列、添加消息、读走消息和控制消息这四种操作。其中创建或打开消息队列使用的函数是msgget(),这里创建的消息队列的数量会受到系统消息队列数量的限制;添加消息队列使用的函数是msgsnd(),它把消息队列添加到已经打开的消息队列末尾;读取消息队列使用的函数是msgrcv(),它把消息从消息队列中读走。

     一、各系统调用
     1、msgget()
     该系统调用创建或打开一个消息队列。

  1. #include
  2. #include
  3. #include
  4. int msgget(key_t, int msgflg)

  5. 调用成功返回消息队列的ID,否则返回-1。参数说明:
  6. > 参数key:是队列的ID,通常去IPC_PRIVATE,意味着创建先的消息队列。
  7. > 参数msgflg:是一些标志位,可以为IPC_CREATE、IPC_EXCL、IPC_NOWAIT或三者的组合。

  8. 在以下两种情况下,该调用将创建一个新的消息队列:
  9. > 如果没有消息队列与键值key相对应,并且msgflg中包含了IPC_CREATE标志位;
  10. > key参数为IPC_PRIVATE。
     2、msgsnd()
     该系统调用向 msgid 代表的消息队列发送一个消息。

  1. #include
  2. #include
  3. #include
  4. int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflag)

  5. 调用成功返回0,否则返回-1。即将发送的消息存储在 msgp 指向的 msgbuf 结构体中,消息的大小由msgsz 指定。msgbuf 结构为消息的基本结构,该结构如下表示:
  6. struct msgbuf {
  7.     long mtype;
  8.     char mtext[BUFSIZ];
  9. };
  10. > mtype 成员代表消息类型,从消息队列中读取消息的一个重要依据就是消息的类型。
  11. > mtext 是消息内容。因此,对于发送消息来说,首先预置一个 msgbuf 缓冲区并写入消息类型和内容,再调用相关的发送函数就可。对于读取消息来说,首先分配一个这样的 msgbuf 结构的缓冲区,然后把消息读入这个缓冲区即可。

  12. 对于发送消息来说,有意义的 msgflg 标志为 IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd 是否等待。造成 msgsnd() 等待的条件有两种:
  13. > 当前消息的大小与当前消息队列中的字节数之和超过了消息队列的总容量。
  14. > 当前消息队列的消息数(单位:“个”)大于等于消息队列的总容量(单位:“字节数”),此时,虽然消息队列中的消息数目很多,但基本都只有一个字节。

  15. msgsnd() 解除阻塞的条件有三个:
  16. > 不满足上述两个条件,即消息队列中有容纳该消息的空间。
  17. > msqid 代表的消息队列被删除。
  18. > 调用 msgsnd 的进程被信号中断。

     3、msgrcv()
     该系统调用从 ID 为 msgid 的消息队列中读取一个消息,并把消息存储在 msgp 指向的 msgbuf 结构中。

  1. #include
  2. #include
  3. #include
  4. int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg)
  5. 调用成功返回读出消息的实际字节数,否则返回-1,参数说明:
  6. > msqid: 为消息队列ID;
  7. > msgp: 为消息返回后的存储地址;
  8. > msgsz: 指定 msgbuf 的 mtext 成员的长度(即消息内容的长度);
  9. > msgtyp: 为请求读取的消息类型;
  10. > msgflg: 为读消息标志。
  11. 关于 msgtyp 有以下说明:
  12. 如果 msgtype=0,接收消息队列的第一个消息;大于0接收队列中消息类型等于这个值的第一个消息;小于0接收消息队列中小于或者等于 msgtype 绝对值的所有消息中的最小一个消息下面我们举一个例子,关于msgtype小于0的使用方法。
  13. 其中,读消息标志 msgflg 可以为以下几个常值的组合。
  14. > IPC_NOWAIT: 如果没有满足条件的消息,调用立即返回,此时, errno = ENOMSG;
  15. > IPC_EXEPT: 与 msgtp>0 配合使用,返回队列中第一个类型不为 msgtyp 的消息;
  16. > IPC_NOERROR: 如果队列中满足条件的消息内容大于所请求的 msgsz 字节,则把该消息截断,截断部分将丢失。
  17. msgrcv() 解除阻塞的条件有三个:
  18. > 消息队列中有了满足条件的消息;
  19. > msgid 代表的消息队列被删除;
  20. > 调用msgrcv() 的进程被信号中断。

     4、msgctl()
     该系统调用对由 msgid 表示的消息队列执行 cmd 操作。

  1. #include
  2. #include
  3. #include
  4. int msgctl(int msgid, int cmd, struct msqid_ds *buf)
  5. 共有三种 cmd 操作:IPC_STAT、IPC_SET、IPC_RMID。
  6. > IPC_STAT: 该命令用来获取消息队列信息,返回的信息存储在 buf 指向的 msqid 结构中。
  7. > IPC_SET: 该命令用来设置消息队列的属性,要设置的属性存储在 buf 指向的 msqid 结构中;
  8. 可设置属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode 以及 msg_qbytes,同时,也影响 msg_ctime 成员。
  9. > IPC_RMID: 删除 msqid 标示的消息队列。
  10. 调用成功返回0,否则返回-1。
     
     二、应用实例
     
     1、接收进程

点击(此处)折叠或打开

  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. struct my_msg_st {
  8. long int my_msg_type;
  9. char some_text[BUFSIZ];
  10. };
  11. int main()
  12. {
  13. int running = 1;
  14. int msgid;
  15. struct my_msg_st some_data;
  16. long int msg_to_receive = -8; //接收消息类型
  17. msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
  18. if (msgid == -1) {
  19. fprintf(stderr, "msgget failed with error: %d\n", errno);
  20. exit(EXIT_FAILURE);
  21. }
  22. while(running) {
  23. if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
  24. msg_to_receive, 0) == -1) {
  25. fprintf(stderr, "msgrcv failed with error: %d\n", errno);
  26. exit(EXIT_FAILURE);
  27. }
  28. printf("You wrote: %s", some_data.some_text);
  29. if (strncmp(some_data.some_text, "end", 3) == 0) {
  30. running = 0;
  31. }
  32. }
  33. if (msgctl(msgid, IPC_RMID, 0) == -1) {
  34. fprintf(stderr, "msgctl(IPC_RMID) failed\n");
  35. exit(EXIT_FAILURE);
  36. }
  37. exit(EXIT_SUCCESS);
  38. }
     2、发送进程

点击(此处)折叠或打开

  1. //发送端msg2代码:
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #define MAX_TEXT 512
  9. struct my_msg_st {
  10. long int my_msg_type;
  11. char some_text[MAX_TEXT];
  12. };
  13. int main()
  14. {
  15. int i = 10;
  16. int running = 1;
  17. struct my_msg_st some_data;
  18. int msgid;
  19. char buffer[BUFSIZ];
  20. msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
  21. if (msgid == -1) {
  22. fprintf(stderr, "msgget failed with error: %d\n", errno);
  23. exit(EXIT_FAILURE);
  24. }
  25. while(running) {
  26. printf("Enter some text: ");
  27. fgets(buffer, BUFSIZ, stdin);
  28. some_data.my_msg_type = i--;
  29. strcpy(some_data.some_text, buffer);
  30. if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
  31. fprintf(stderr, "msgsnd failed\n");
  32. exit(EXIT_FAILURE);
  33. }
  34. if (strncmp(buffer, "end", 3) == 0) {
  35. running = 0;
  36. }
  37. }
  38. exit(EXIT_SUCCESS);
  39. }


参考资料:
1、《ARM嵌入式linux系统开发技术详解》 杨水清 等
2、作者:丝缘天下 网址:

     

阅读(1204) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~