首页 > 代码库 > 进程间通信---IPC对象 之 消息队列
进程间通信---IPC对象 之 消息队列
IPC对象,既我们所说的进程间通信,下面就来总结一下都有哪些方式以及怎么使用。
一 消息队列
1 消息队列的创建:
int msgget(key_t key, int msgflg);
功能:获取指定的key值的消息队列ID
参数:
@key
<1>IPC_PRIVATE:每次都会创建一个新的消息队列 [用在亲缘关系的进程间痛惜]
<2>ftok函数获的key [用在非亲缘关系进程间通信]
key_t ftok(const char *pathname, int proj_id);
功能:根据文件的ID 和 proj_id的低8bit产生一个key值
参数:
@pathname 一个文件名
@proj_id 一个字符
返回值:
成功返回key,失败返回-1
@msgflg :IPC_CREAT , IPC_EXCL
IPC_CREAT | 0666 -> 如果执行的key的消息队列不存在,则创建新的消息队列
IPC_CREAT | IPC_EXCL -> 判别指定key的消息队列是否存在,如果存在则报错
返回值:
成功返回消息队列ID,失败返回-1
2 添加消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
@msqid 消息队列的ID
@msgp 消息存放的地址
@msgsz 消息正文的大小
@msgflg 0:阻塞的方式调用 IPC_NOWAIT:非阻塞的方式调用
返回值:成功返回0,失败返回-1
消息结构体:
typedef struct
{
//第一个字段必须是消息类型
long type;
//消息正文部分
char buf[1024];
int pid;
..
}MSG;
//计算消息正文的大小
#define MTXT_SIZE (sizeof(MSG) - sizeof(long))
3 接受消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
@msqid 消息队列的ID
@msgp 消息存放的地址
@msgsz 消息正文的大小
@msgtyp 消息的类型
@msgflg 0:阻塞的方式调用 IPC_NOWAIT:非阻塞的方式调用
返回值:成功返回接受的消息正文大小,失败返回-1
我们可以通过下面的一个例子来了解消息队列的具体通信方式:
就是对于不是亲缘关系的两个进程A B进行通信:
都可以实现双方的收发:
#include <head.h> //the struct of mesage typedef struct { long type; char buf[1024]; int pid; }MSG; #define MTXT_SIZE (sizeof(MSG) - sizeof(long)) #define TYPEA 100 #define TYPEB 200 // ./a.out filename int main(int argc, const char *argv[]) { if(argc < 2) { fprintf(stderr,"Usage : %s argv[1]\n",argv[0]); exit(EXIT_FAILURE); } int key; key = ftok(argv[1],'A'); //get key if(key < 0) { fprintf(stderr,"Fail to ftok \n",strerror(errno)); exit(EXIT_FAILURE); } printf("key : %#x\n",key); int msg_id; msg_id = msgget(key,IPC_CREAT | 0666); //create mesage queue if(msg_id < 0) { perror("Fail to msgget"); exit(EXIT_FAILURE); } printf("msg_id :%d\n",msg_id); MSG msg; pid_t pid; pid = fork(); if(pid < 0) { perror("Fail to fork"); exit(EXIT_FAILURE); } if(pid == 0) { while(1) { ssize_t ret; ret = msgrcv(msg_id,&msg,MTXT_SIZE,TYPEA,0); if(ret < 0) { perror("Fail to msgrcv"); exit(EXIT_FAILURE); } printf("TYPE :%ld\n",msg.type); printf("PID :%d\n",msg.pid); printf("MTXT :%s\n",msg.buf); if(strncmp(msg.buf,"quit",4) == 0) { kill(getppid(),SIGUSR1); break; } } } if(pid > 0) { msg.pid = getpid(); msg.type = TYPEB; while(1) { printf(">"); fgets(msg.buf,sizeof(msg.buf),stdin); msg.buf[strlen(msg.buf)-1] = '\0'; if(msgsnd(msg_id,&msg,MTXT_SIZE,0)< 0) { perror("Fail to msgsnd"); exit(EXIT_FAILURE); } if(strncmp(msg.buf,"quit",4) == 0) { kill(getpid(),SIGUSR1);//使退出一个时全都退出进程 break; } } } return 0; }
另一个:
#include <head.h> //the struct of mesage typedef struct { long type; char buf[1024]; int pid; }MSG; #define MTXT_SIZE (sizeof(MSG) - sizeof(long)) #define TYPEA 200 #define TYPEB 100 // ./a.out filename int main(int argc, const char *argv[]) { MSG msg; int key; int msg_id; pid_t pid; if(argc < 2) { fprintf(stderr,"Usage : %s argv[1]\n",argv[0]); exit(EXIT_FAILURE); } key = ftok(argv[1],'A'); //get key if(key < 0) { fprintf(stderr,"Fail to ftok \n",strerror(errno)); exit(EXIT_FAILURE); } printf("key : %#x\n",key); msg_id = msgget(key,IPC_CREAT | 0666); //create mesage queue if(msg_id < 0) { perror("Fail to msgget"); exit(EXIT_FAILURE); } printf("msg_id :%d\n",msg_id); pid = fork(); if(pid < 0) { perror("Fail to fork"); exit(EXIT_FAILURE); } if(pid == 0) { while(1) { ssize_t ret; ret = msgrcv(msg_id,&msg,MTXT_SIZE,TYPEA,0); if(ret < 0) { perror("Fail to msgrcv"); exit(EXIT_FAILURE); } printf("TYPE :%ld\n",msg.type); printf("PID :%d\n",msg.pid); printf("MTXT :%s\n",msg.buf); if(strncmp(msg.buf,"quit",4) == 0) { kill(getppid(),SIGUSR1); break; } } } if(pid > 0) { msg.pid = getpid(); msg.type = TYPEB; while(1) { printf(">"); fgets(msg.buf,sizeof(msg.buf),stdin); msg.buf[strlen(msg.buf)-1] = '\0'; if(msgsnd(msg_id,&msg,MTXT_SIZE,0)< 0) { perror("Fail to msgsnd"); exit(EXIT_FAILURE); } if(strncmp(msg.buf,"quit",4) == 0) { kill(getpid(),SIGUSR1); if(msgctl(msg_id,IPC_RMID,NULL) < 0) { perror("Fail to msgctl"); exit(EXIT_FAILURE); } break; } } } return 0; }
好了,上面就是有关消息队列的相关了解。