Linux下进程间通信--消息队列
消息队列的定义遍地都是,不想移驾,请看下文:
一、定义:
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。
每个数据块都被认 为是有一个类型,接收者进程接收的数据块可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步和阻塞问题。
消息队列与管道不同的是,消息队列是基于消息的, 而管道是基于字节流的,且消息队列的读取不一定是先入先出。
消息队列与命名管道有一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)
关于上下限:
二、IPC对象数据结构
内核为每个IPC对象维护一个数据结构(/usr/include/linux/ipc.h)
struct ipc_perm { key_t __key; /* Key supplied to xxxget(2) */ uid_t uid; /* Effective UID of owner */ gid_t gid; /* Effective GID of owner */ uid_t cuid; /* Effective UID of creator */ gid_t cgid; /* Effective GID of creator */ unsigned short mode; /* Permissions */
unsigned short __seq;/* Sequence number */ };
消息队列,共享内存和信号量都有这样一个共同的数据结构。
三、消息队列结构:
可以看到第一个条目就是IPC结构体,即是共有的,后面的都是消息队列所私有的成员,消息队列是用链表实现的。
四、相关函数解释:
int msgget(key_t, key, int msgflg);
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
struct my_message{ long int message_type; /* The data you wish to transfer*/ };
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
int msgctl(int msgid, int command, struct msgid_ds *buf);
struct msgid_ds { uid_t shm_perm.uid; uid_t shm_perm.gid; mode_t shm_perm.mode; };
3.comm.h
4.comm.c
代码主要就贴comm.c里的:
#include"comm.h" static int com_msg_queue(int flags) { key_t _key = ftok(_PROJ_NAME_,_PROJ_ID_); if(_key < 0) { perror("ftok"); return -1; } int msg_id = msgget(_key,flags); // if(msg_id < 0) { perror("msgget"); } return msg_id; } int create_msg_queue() { int flags = IPC_CREAT | IPC_EXCL | 0644; return com_msg_queue(flags); } int get_msg_queue() { int flags = IPC_CREAT; return com_msg_queue(flags); } int destroy_msg_queue(int msg_id) { if(msgctl(msg_id,IPC_RMID,NULL) < 0) { perror("msgctl"); return -1; } return 0; } int send_msg(int msg_id,int t,const char* msg) { struct msgbuf _msg; _msg.mtype = t; strncpy(_msg.mtext,msg,strlen(msg)+1); if(msgsnd(msg_id,&_msg,sizeof(_msg.mtext),0) < 0) { perror("msgsnd"); return -1; } return 0; } int recv_msg(int msg_id,int t,char* out) { struct msgbuf _msg; _msg.mtype = t; memset(_msg.mtext,'\0',sizeof(_msg.mtext)); if(msgrcv(msg_id,&_msg,sizeof(_msg.mtext),t,0) < 0) { perror("msgrcv"); return -1; } else { strcpy(out,_msg.mtext); } return 0; }分析:主要是两个.C文件,两个main函数,两个进程,一个进程发送,一个进程接受,模拟实现连个进程间的通信,代码中最后的两个函数,一个是发送,一个是接受;
六、消息队列与命名管道的比较
消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。
在命名管道中,发送数据用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们对每个数据都有一个最大长度的限制。
与命名管道相比,消息队列的优势在于:
1、消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。
2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。
3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。
赐教!