首页 > 代码库 > Linux消息队列实践(1)

Linux消息队列实践(1)

消息队列基本概念

    消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法(仅局限与本机)

    每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

    消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)

 

管道 vs. 消息队列:

管道: 流管道          消息: 有边界

   先进先出            可以后进入、先出来

 

消息队列大小三大限制

   cat /proc/sys/kernel/msgmax  #最大消息长度限制

   cat /proc/sys/kernel/msgmnb  #消息队列总的字节数

   cat /proc/sys/kernel/msgmni  #消息条目数

 

 

IPC对象数据结构

   内核为每个IPC对象维护一个数据结构

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. struct ipc_perm  
  2. {  
  3.     key_t          __key;       /* Key supplied to msgget(2) */  
  4.     uid_t          uid;         /* Effective UID of owner */  
  5.     gid_t          gid;         /* Effective GID of owner */  
  6.     uid_t          cuid;        /* Effective UID of creator */  
  7.     gid_t          cgid;        /* Effective GID of creator */  
  8.     unsigned short mode;        /* Permissions */  
  9.     unsigned short __seq;       /* Sequence number */  
  10. };  

 

消息队列特有的结构

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. struct msqid_ds  
  2. {  
  3.     struct ipc_perm msg_perm;     /* Ownership and permissions */  
  4.     time_t          msg_stime;    /* Time of last msgsnd(2) */  
  5.     time_t          msg_rtime;    /* Time of last msgrcv(2) */  
  6.     time_t          msg_ctime;    /* Time of last change */  
  7.     unsigned long   __msg_cbytes; /* Current number of bytes in 
  8.                                                 queue (nonstandard) */  
  9.     msgqnum_t       msg_qnum;     /* Current number of messages 
  10.                                                 in queue */  
  11.     msglen_t        msg_qbytes;   /* Maximum number of bytes 
  12.                                                 allowed in queue */  
  13.     pid_t           msg_lspid;    /* PID of last msgsnd(2) */  
  14.     pid_t           msg_lrpid;    /* PID of last msgrcv(2) */  
  15. };  

 

消息队列在内核中的表示


消息队列函数示例

msgget函数 

功能:用来创建访问一个消息队列

原型:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int msgget(key_t key, int msgflg);  

参数:

    key: 某个消息队列的名字

    msgflg:由九个权限标志构成,如0644,它们的用法和创建文件时使用的mode模式标志是一样的(但是消息队列没有x(执行)权限)

 

返回值:

   成功返回消息队列编号,即该消息队列的标识码;失败返回-1

 

编程实践

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //实践1:  IPC_PRIVATE:宏,值为0  
  2. int main()  
  3. {  
  4.   //IPC_PRIVATE每次创建的消息队列的描述符都是不同的!  
  5.   //因此,计时MessageID(key)传送给其他进程(除非有关联的进程),  
  6.   //其他进程也无法使用该消息队列(血缘fork除外)  
  7.     int msgid = msgget(IPC_PRIVATE,0666);  
  8.     if (msgid < 0)  
  9.     {  
  10.         //如果消息队列不存在,则打开错误,errno=ENOENT  
  11.         if (errno == ENOENT)  
  12.         {  
  13.             cout << "ENOENT" << endl;  
  14.         }  
  15.         err_exit("mesget error");  
  16.     }  
  17.     else  
  18.     {  
  19.         cout << "msgid = " << msgid << endl;  
  20.     }  
  21.   
  22.     return 0;  
  23. }  
  24. /** 
  25.   IPC_PRIVATE创建的消息队列,只能用在与当前进程有关系的进程中使用! 
  26. */  


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //实践2:  IPC_CREAT  
  2. int main()  
  3. {  
  4.     //指定IPC_CREAT,则一定会创建消息队列  
  5.     int msgid = msgget(0x1235,0666|IPC_CREAT);  
  6.     if (msgid < 0)  
  7.     {  
  8.         //如果消息队列不存在,则打开错误,errno=ENOENT  
  9.         if (errno == ENOENT)  
  10.         {  
  11.             cout << "ENOENT" << endl;  
  12.         }  
  13.         err_exit("mesget error");  
  14.     }  
  15.     else  
  16.     {  
  17.         cout << "msgid = " << msgid << endl;  
  18.     }  
  19.   
  20.     return 0;  
  21. }  


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //实践3:  IPC_CREAT|IPC_EXCL  
  2. int main()  
  3. {  
  4.     //指定IPC_EXCL, 如果已经存在,则报告文件已经存在(错误)  
  5.     int msgid = msgget(0x1235,0666|IPC_CREAT|IPC_EXCL);  
  6.     if (msgid < 0)  
  7.     {  
  8.         err_exit("mesget error");  
  9.     }  
  10.     else  
  11.     {  
  12.         cout << "msgid = " << msgid << endl;  
  13.     }  
  14.   
  15.     return 0;  
  16. }  




[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //实践4:低权限创建,高权限打开  
  2. int main()  
  3. {  
  4.     //低权限创建  
  5.     int msgid = msgget(0x255,0444 | IPC_CREAT);  
  6.     if (msgid < 0)  
  7.     {  
  8.         err_exit("mesget error");  
  9.     }  
  10.     else  
  11.     {  
  12.         cout << "Create Mes OK, msgid = " << msgid << endl;  
  13.     }  
  14.   
  15.     //高权限打开  
  16.     msgid = msgget(0x255,0644 | IPC_CREAT);  
  17.     if (msgid < 0)  
  18.     {  
  19.         err_exit("mesget error");  
  20.     }  
  21.     else  
  22.     {  
  23.         cout << "Create Mes OK, msgid = " << msgid << endl;  
  24.     }  
  25.   
  26.     return 0;  
  27. }  


msgget函数参数关系图

 

Linux消息队列实践(1)