linux进程通信-消息

消息队列是消息的链接表,包括Posix消息队列system V消息队列。消息队列用于运行于同一台机器上的进程间通信,它
和管道很相似,有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了
信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。 我们可以用流管道或者套接口的方式来取代它。

查询系统消息队列:ipcs -q

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

int msgget(key_t key, int msgflg);

int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);

int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);


C代码
  1. /*msgserver.c*/ 
  2.  
  3. #include <stdlib.h> 
  4. #include <string.h> 
  5. #include <errno.h> 
  6. #include <sys/types.h> 
  7. #include <sys/ipc.h> 
  8. #include <sys/msg.h> 
  9. #include <sys/stat.h> 
  10.  
  11. #define   MSG_FILE "msgserver.c" 
  12. #define   BUFFER 255  
  13. #define   PERM S_IRUSR|S_IWUSR 
  14. /* 服务端创建的消息队列最后没有删除,我们要使用ipcrm命令来删除的 */ 
  15. /* ipcrm -q <msqid> */ 
  16.  
  17. struct msgtype  
  18. {  
  19.     long mtype;  
  20.     char buffer[BUFFER+1];  
  21. };  
  22.  
  23. int main()  
  24. {  
  25.     struct msgtype msg;  
  26.     key_t key;  
  27.     int msgid;  
  28.      
  29.     if((key=ftok(MSG_FILE,'a'))==-1)  
  30.     {  
  31.         fprintf(stderr,"Creat Key Error:%s\n", strerror(errno));  
  32.         exit(1);  
  33.     }  
  34.  
  35.     if((msgid=msgget(key, PERM|IPC_CREAT|IPC_EXCL))==-1)  
  36.     { 
  37.         fprintf(stderr, "Creat Message Error:%s\n", strerror(errno));  
  38.         exit(1); 
  39.     }  
  40.     printf("msqid = %d\n", msgid); 
  41.     while(1) 
  42.     {  
  43.         msgrcv(msgid, &msg, sizeof(struct msgtype), 1, 0);  
  44.         fprintf(stderr,"Server Receive:%s\n", msg.buffer);  
  45.         msg.mtype = 2;  
  46.         msgsnd(msgid, &msg, sizeof(struct msgtype), 0);  
  47.     }  
  48.     exit(0);  
  49. }    
C代码
  1. /* msgclient.c */ 
  2.  
  3. #include <stdio.h> 
  4. #include <stdlib.h> 
  5. #include <string.h> 
  6. #include <errno.h> 
  7. #include <sys/types.h> 
  8. #include <sys/ipc.h> 
  9. #include <sys/msg.h> 
  10. #include <sys/stat.h> 
  11.  
  12. #define   MSG_FILE "msgserver.c" 
  13. #define   BUFFER 255  
  14. #define   PERM S_IRUSR|S_IWUSR 
  15.  
  16. struct msgtype {  
  17.     long mtype;  
  18.     char buffer[BUFFER+1];  
  19. };  
  20.  
  21. int main(int argc,char **argv)  
  22. {  
  23.     struct msgtype msg;  
  24.     key_t key;  
  25.     int msgid;  
  26.      
  27.     if(argc != 2)  
  28.     {  
  29.         fprintf(stderr,"Usage:%s string\n", argv[0]);  
  30.         exit(1);  
  31.     }  
  32.      
  33.     if((key=ftok(MSG_FILE,'a'))==-1)  
  34.     {  
  35.         fprintf(stderr,"Creat Key Error:%s\n", strerror(errno));  
  36.         exit(1);  
  37.     }  
  38.      
  39.     if((msgid=msgget(key, PERM))==-1)  
  40.     {  
  41.         fprintf(stderr,"Creat Message  Error:%s\n", strerror(errno));  
  42.         exit(1);  
  43.     }  
  44.      
  45.     msg.mtype = 1;  
  46.     strncpy(msg.buffer, argv[1], BUFFER);  
  47.     msgsnd(msgid, &msg, sizeof(struct msgtype), 0);   
  48.     memset(&msg, '\0',sizeof(struct msgtype));  
  49.     msgrcv(msgid, &msg, sizeof(struct msgtype), 2, 0);  
  50.     fprintf(stderr, "Client receive:%s\n", msg.buffer);  
  51.     exit(0); 
  52. }   




posix消息:

消息队列可以当做一个消息链表,不同于FIFO和管道,某个进程往一个消息队列写入消息之前,不需要另外进程在该队列上等待消息的到达。

对posix消息队列的读总是返回最高优先级的最早消息。

常用函数:

创建或者打开一个消息队列:

       #include <fcntl.h>           /* For O_* constants */
       #include <sys/stat.h>        /* For mode constants */
       #include <mqueue.h>

       mqd_t mq_open(const char *name, int oflag);
       mqd_t mq_open(const char *name, int oflag, mode_t mode,

                     struct mq_attr *attr);

关闭消息队列:

       #include <mqueue.h>

       int mq_close(mqd_t mqdes);
删除消息队列:

posix消息队列具备随内核的持续性,就是说即使当前没有进程打开某个消息队列,该队列上的消息也将一直存在。

       #include <mqueue.h>

       int mq_unlink(const char *name);

要真正的删除一个消息队列得这样:调用mq_unlink并让它的引用计数(close一次减少1)达到0。

获取消息队列属性:

       #include <mqueue.h>

 

       int mq_getattr(mqd_t mqdes, struct mq_attr *attr);

 

       int mq_setattr(mqd_t mqdes, struct mq_attr *newattr,

                        struct mq_attr *oldattr);

其中消息队列属性结构体如下:
           struct mq_attr {
               long mq_flags;       /* Flags: 0 or O_NONBLOCK */
               long mq_maxmsg;      /* Max. # of messages on queue */
               long mq_msgsize;     /* Max. message size (bytes) */
               long mq_curmsgs;     /* # of messages currently in queue */
           };

接收和发送消息:
       #include <mqueue.h>

       int mq_send(mqd_t mqdes, const char *msg_ptr,
                     size_t msg_len, unsigned msg_prio);
       #include <mqueue.h>

       ssize_t mq_receive(mqd_t mqdes, char *msg_ptr,
                          size_t msg_len, unsigned *msg_prio);


消息队列限制:
总共有四个限制,分别为:
mq_mqxmsg;mq_msgsize;
MQ_OPEN_MAX;MQ_PRIO_MAX:这两个是在<unistd.h>头文件里定义的,可以用sysconf获取。


例子:创建消息队列
代码:
1 //mqcreate.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <unistd.h>
04 #include <mqueue.h>
05 #include <fcntl.h>
06 #include <sys/stat.h>
07 #define FILEMODE (S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP)
08 struct mq_attr attr;//消息队列属性结构体
09  
10 int main(int argc, char **argv)
11 {
12     int c, flags;
13     mqd_t mqd;
14  
15     flags = O_RDWR | O_CREAT;
16     while((c = getopt(argc, argv, "em:z:")) != -1) {//处理参数,带冒号的表示后面有参数的
17         switch(c) {
18             case 'e':
19                 flags |= O_EXCL;
20                 printf("the optind is :%d\n",optind);
21                 break;
22             case 'm':
23                 attr.mq_maxmsg = atol(optarg);
24                 printf("the optind is :%d\n",optind);
25                 break;
26             case 'z':
27                 attr.mq_msgsize = atol(optarg);
28                 printf("the optind is :%d\n",optind);
29                 break;
30         }
31     }
32     if (optind != argc - 1) {
33         printf("usage: mqcreate [-e] [-m maxmsg -z msgsize] <name>");
34         exit(0);
35     }
36      
37     if ((attr.mq_maxmsg != 0 && attr.mq_msgsize == 0) || (attr.mq_maxmsg == 0 && attr.mq_msgsize !=0)){
38         printf("must specify both -m maxmsg and -z msgsize");
39         exit(0);
40     }
41  
42     mqd = mq_open(argv[optind], flags, FILEMODE, (attr.mq_maxmsg != 0) ? &attr : NULL);
43     mq_close(mqd);
44     exit(0);
45 }

例子:发送消息
代码:
1 //mqsend.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <unistd.h>
04 #include <mqueue.h>
05  
06  
07 int main(int argc, char **argv)
08 {
09     mqd_t mqd;
10     void *ptr;
11     size_t len;
12     unsigned int prio;
13  
14     if (argc != 4) {
15         printf("usage: mqsend <name> <#bytes> <priority>");
16         exit(0);
17     }
18     len = atoi(argv[2]);
19     prio = atoi(argv[3]);
20      
21     if ((mqd = mq_open(argv[1], O_WRONLY)) == -1){
22         printf("open error");
23         exit(0);
24     }
25     ptr = calloc(len, sizeof(char));
26     mq_send(mqd, ptr, len, prio);
27     exit(0);
28 }

例子:读取一个消息
代码:
1 //mqrecieve.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <unistd.h>
04 #include <mqueue.h>
05  
06 int main(int argc, char **argv)
07 {
08     int c, flags;
09     mqd_t mqd;
10     ssize_t n;
11     unsigned int prio;
12     void *buff;
13     struct mq_attr attr;
14     flags = O_RDONLY;
15     while((c = getopt(argc, argv, "n")) != -1){
16         switch(c) {
17             case 'n':
18                 flags |= O_NONBLOCK;
19                 break;
20         }
21     }
22     if (optind != argc-1) {
23         printf("usage: mqreceive [-n] <name>");
24         exit(0);
25     }
26  
27     mqd = mq_open(argv[optind], flags);
28     mq_getattr(mqd, &attr);
29  
30     buff = malloc(attr.mq_msgsize);
31  
32     n = mq_receive(mqd, buff, attr.mq_msgsize, &prio);
33     printf("read %ld bytes, priority = %u\n",(long) n,prio);
34     exit(0);
35 }

你可能感兴趣的:(linux,struct,File,System,buffer,Constants)