IPC通信:Posix消息队列读,写
创建消息队列的程序:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <mqueue.h> //头文件 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 #include <errno.h> 9 10 #define MQ_NAME ("/tmp") 11 #define MQ_FLAG (O_RDWR | O_CREAT | O_EXCL) // 创建MQ的flag 12 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) // 设定创建MQ的权限 13 14 int main() 15 16 { 17 mqd_t posixmq; 18 int rc = 0; 19 20 /* 21 函数说明:函数创建或打开一个消息队列 22 返回值:成功返回消息队列描述符,失败返回-1,错误原因存于errno中 23 */ 24 posixmq = mq_open(MQ_NAME, MQ_FLAG, FILE_MODE, NULL); 25 26 if(-1 == posixmq) 27 { 28 perror("创建MQ失败"); 29 exit(1); 30 } 31 32 /* 33 函数说明:关闭一个打开的消息队列,表示本进程不再对该消息队列读写 34 返回值:成功返回0,失败返回-1,错误原因存于errno中 35 */ 36 rc = mq_close(posixmq); 37 if(0 != rc) 38 { 39 perror("关闭失败"); 40 exit(1); 41 } 42 43 #if 0 44 /* 45 函数说明:删除一个消息队列,好比删除一个文件,其他进程再也无法访问 46 返回值:成功返回0,失败返回-1,错误原因存于errno中 47 */ 48 rc = mq_unlink(MQ_NAME); 49 if(0 != rc) 50 { 51 perror("删除失败"); 52 exit(1); 53 } 54 55 return 0; 56 #endif 57 }
编译并执行:
1 root@linux:/mnt/hgfs/C_libary# gcc -o crtmq crtmq.c -lrt 2 root@linux:/mnt/hgfs/C_libary# ./crtmq 3 程序并没有删除消息队列(消息队列有随内核持续性),如再次执行该程序则会给出错误信息: 4 root@linux:/mnt/hgfs/C_libary# ./crtmq 5 创建MQ失败: File exit(0)
向消息队列写消息的程序:
消息队列的读写主要使用下面两个函数: /*头文件*/ #include <mqueue.h> /*返回:若成功则为消息中字节数,若出错则为-1 */ int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); /*返回:若成功则为0, 若出错则为-1*/ ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); /*消息队列属性结构体*/ 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 */ };
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <mqueue.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 #include <errno.h> 9 10 /*向消息队列发送消息,消息队列名及发送的信息通过参数传递*/ 11 int main(int argc, char *argv[]) 12 { 13 mqd_t mqd; 14 char *ptr; 15 size_t len; 16 unsigned int prio; 17 int rc; 18 19 if(argc != 4) 20 { 21 printf("Usage: sendmq <name> <bytes> <priority>\n"); 22 exit(1); 23 } 24 25 len = atoi(argv[2]); 26 prio = atoi(argv[3]); 27 28 //只写模式找开消息队列 29 mqd = mq_open(argv[1], O_WRONLY); 30 if(-1 == mqd) 31 { 32 perror("打开消息队列失败"); 33 exit(1); 34 } 35 36 // 动态申请一块内存 37 ptr = (char *) calloc(len, sizeof(char)); 38 if(NULL == ptr) 39 { 40 perror("申请内存失败"); 41 mq_close(mqd); 42 exit(1); 43 } 44 45 /*向消息队列写入消息,如消息队列满则阻塞,直到消息队列有空闲时再写入*/ 46 rc = mq_send(mqd, ptr, len, prio); 47 if(rc < 0) 48 { 49 perror("写入消息队列失败"); 50 mq_close(mqd); 51 exit(1); 52 } 53 54 // 释放内存 55 free(ptr); 56 return 0; 57 }
编译并执行:
1 root@linux:/mnt/hgfs/C_libary# gcc -o sendmq sendmq.c -lrt 2 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 15 3 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 16 4 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 17 5 root@linux:/mnt/hgfs/C_libary# ./sendmq /tmp 30 18
上面先后向消息队列“/tmp”写入了四条消息,因为先前创建的消息队列只允许存放3条消息,本次第四次写入时程序会阻塞。直到有另外进程从消息队列取走消息后本次写入才成功返回。
读消息队列:
#include <stdio.h> #include <stdlib.h> #include <mqueue.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> /*读取某消息队列,消息队列名通过参数传递*/ int main(int argc, char *argv[]) { mqd_t mqd; struct mq_attr attr; char *ptr; unsigned int prio; size_t n; int rc; if(argc != 2) { printf("Usage: readmq <name>\n"); exit(1); } /*只读模式打开消息队列*/ mqd = mq_open(argv[1], O_RDONLY); if(mqd < 0) { perror("打开消息队列失败"); exit(1); } // 取得消息队列属性,根据mq_msgsize动态申请内存 rc = mq_getattr(mqd, &attr); if(rc < 0) { perror("取得消息队列属性失败"); exit(1); } /*动态申请保证能存放单条消息的内存*/ ptr = calloc(attr.mq_msgsize, sizeof(char)); if(NULL == ptr) { printf("动态申请内存失败\n"); mq_close(mqd); exit(1); } /*接收一条消息*/ n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio); if(n < 0) { perror("读取失败"); mq_close(mqd); free(ptr); exit(1); } printf("读取 %ld 字节\n 优先级为 %u\n", (long)n, prio); return 0; }
编译并执行:
1 root@linux:/mnt/hgfs/C_libary# vi readmq.c 2 root@linux:/mnt/hgfs/C_libary# vi readmq.c 3 root@linux:/mnt/hgfs/C_libary# gcc -o readmq readmq.c -lrt 4 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp 5 读取 30 字节 6 优先级为 18 7 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp 8 读取 30 字节 9 优先级为 17 10 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp 11 读取 30 字节 12 优先级为 16 13 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp 14 读取 30 字节 15 优先级为 15 16 root@linux:/mnt/hgfs/C_libary# ./readmq /tmp
程序执行五次,第一次执行完,先前阻塞在写处的程序成功返回。第五次执行,因为消息队列已经为空,程序阻塞。直到另外的进程向消息队列写入一条消息。另外,还可以看出Posix消息队列每次读出的都是消息队列中优先级最高的消息。