System V 进程间通信之消息队列

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liu_zhen_kai/article/details/82053214

消息队列的基本模型
消息队列中有两个数据结构

  • msqid_ds消息队列数据结构:描述着整个消息队列的属性包括:消息队列的权限,消息队列的拥有者,指向消息队列第一个以及最后一个成员的指针
  • msg消息队列的主体数据结构包括:消息类型,消息大小,消息位置以及下一消息。
 60 #define MSG_MEM_SCALE 32
 61 
 62 #define MSGMNI    16   /* <= IPCMNI */     /* max # of msg queue identifiers */
 63 #define MSGMAX  8192   /* <= INT_MAX */   /* max size of message (bytes) */
 64 #define MSGMNB 16384   /* <= INT_MAX */   /* default max size of a message queue */

在centos 6.5中规定:

  • 默认情况下系统最多存在16个消息队列
  • 每个消息队列最大为16384个字节
  • 消息队列的每个节点最大为8192个字节

Linux消息队列管理
1.在使用一个消息队列之前,需要用msgget函数来创建一个消息队列,函数如下:

int msgget(key_t key, int msgflg);
    参数分析
        key:
        系统为每个ipc机制都分配了唯一的ID,可以自己定义,或者由ftok函数来获取,
        只要任意进程用到相同的ID,即可实现进程间通信。
        msgflg:
        其中可以选择:IPC_CREAT:如果key不存在,就创建一个key,若key存在则返回ID
                    IPC_EXCL:如果key存在,返回失败
                    IPC_NOWAIT:如果需要等待,直接返回错误

        低位用来确定访问权限,最终值为perm&umask,与|选项一起使用
    返回值:
        返回一个msqid,即为key的句柄

2.消息队列属性控制用msgctl函数来实现

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
    参数分析
        msqid:key的操作句柄,一般为msgget的返回值
        cmd:执行的控制命令,包括选项有:
            IPC_STAT:读取消息队列属性,并将msqid__ds结构体信息放入buf中
            IPC_SET:读取消息队列属性,按buf中的值设定消息队列中去设定所属用户,所属组,权限等信息
            IPC_RMID:删除消息队列
            IPC_INFO:读取消息队列的
        buf:
            msqid_id结构体类型变量,用于储存信息或者修改消息队列信息


     返回值:
         大多数成功返回0,失败返回-1

3.发送消息到消息队列msgsnd函数

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    参数分析:
        msqid:
            消息队列的句柄,即要发送到的消息队列
        msgp:
            指向用户定义的缓冲区,是一个需要在使用时自己定义的数据结构
            struct msgbuf{
                long mtype;//消息类型
                char mtext[1];//消息内容
            };
        msgsz:
            发出信息的大小。
        msgflg:
            用来指定在达到系统为消息队列规定的边界时所采取的操作
                1.IPC_NOWAIT:如果需要等待,则不发送消息直接返回,错误信息:EAGAIN
                2.如果设置为0,则阻塞调用进程

4.从消息队列接受信息msgrcv

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);
    参数分析:
        msqlid:
            函数从消息队列msqid中接收信息。
        msgp:
            从消息队列接收的信息放入msgp当中
        msgsz:
            用于指定mtext的大小,收到的消息大于msgsz并且msgflg&MSG_NOERRER为真,则
            截取部分将丢失。
        msgtyp用于指定接收到的消息的类型,具体如下:
            1.等于0:接收队列中第一条消息,任意类型
            2.大于0:接收队列中第一条为这个类型的消息
            3.小于0:接收第一条最低消息
        msflg:
            为设置选项

消息队列的应用实例
用消息队列来实现一个聊天程序

  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <unistd.h>
  6 #include <string.h>
  7 #include <sys/types.h>
  8 #include <sys/ipc.h>
  9 #include <sys/msg.h>
 10 
 11 struct msgbuf{
 12     int type;
 13     char ptr[0];
 14 };
 15 
 16 int main(int argc, char* argv[])
 17 {
 18     key_t key = ftok(argv[1], 100);
 19     int msgid;
 20     msgid = msgget(key, IPC_CREAT|0644);//找到key的句柄
 21     pid_t pid = fork();
 22     if(pid < 0)
 23     {
 24         perror("fork"),
 25             exit(1);
 26     }
 27         else if(pid == 0)//子进程发送消息
 28         {
 29             while(1){
 30                 printf("please input msg:");
 31                 char buf[128];
 32                 fgets(buf, 128, stdin);
 33                 struct msgbuf* ptr = (struct msgbuf*)malloc((sizeof(struct msgbuf) + strlen(buf) + 1));
 34                 ptr->type = 1;
 35                 memcpy(ptr->ptr, (const char*)buf, strlen(buf) + 1);
  37                 msgsnd(msgid, ptr, strlen(buf) + 1, 0);
 38                 free(ptr);
 39             }
 40         }
 41             else
 42                 {
 43                     struct msgbuf{
 44                         int type;
 45                         char ptr[1024];
 46                     };
 47                         while(1){
 48                             struct msgbuf msgbuf;
 49                             memset(&msgbuf, '\0', sizeof(msgbuf));
 50                             msgrcv(msgid, &msgbuf, 1024, 2, 0);
 51                             printf("%s\n", msgbuf.ptr);
 52                         }
 53                 }
 54 
 55     return 0;
 56 }
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <unistd.h>
  6 #include <string.h>
  7 #include <sys/types.h>
  8 #include <sys/ipc.h>
  9 #include <sys/msg.h>
 10 
 11 struct msgbuf{
 12     int type;
 13     char ptr[0];
 14 };
 15 
 16 int main(int argc, char* argv[])
 17 {
 18     key_t key = ftok(argv[1], 100);
 19     int msgid;
 20     msgid = msgget(key, IPC_CREAT|0644);//找到key的句柄
 21     pid_t pid = fork();
 22     if(pid < 0)
 23     {
 24         perror("fork"),
 25             exit(1);
 26     }
 27         else if(pid == 0)//子进程发送消息
 28         {
 29             while(1){
 30                 printf("please input msg:");
 31                 char buf[128];
 32                 fgets(buf, 128, stdin);
 33                 struct msgbuf* ptr = (struct msgbuf*)malloc((sizeof(struct msgbuf) + strlen(buf) + 1));
 34                 ptr->type = 2;
 35                 memcpy(ptr->ptr, (const char*)buf, strlen(buf) + 1);
 36                 //收发信息必须由传输结构体完成,结构体就是桥梁
 37                 msgsnd(msgid, ptr, strlen(buf) + 1, 0);
 38                 free(ptr);
 39             }
 40         }
 41             else
 42                 {
 43                     struct msgbuf{
 44                         int type;
 45                         char ptr[1024];
 46                     };
 47                         while(1){
 48                             struct msgbuf msgbuf;
 49                             memset(&msgbuf, '\0', sizeof(msgbuf));
 50                             msgrcv(msgid, &msgbuf, 1024, 1, 0);
 51                             printf("%s\n", msgbuf.ptr);
 52                         }
 53                 }
 54 
 55     return 0;
 56 }

这样就实现了聊天接收发送,不再是单向传输了。

猜你喜欢

转载自blog.csdn.net/liu_zhen_kai/article/details/82053214