消息队列提供了一个进程向另一个进程发送数据块的方法,每个数据块都被认为是有一个类型的,这个类型下文中是用常量is_client_snd和is_server_snd来表示的
消息队列相比管道来说的优点是避免了阻塞。
系统调用函数:
- #include<sys/types.h>
#include<sys/ipc.h>
原型:key_t ftok(const char* pathname,int proj_id);
参数:pathname为一个已存在的、可获得信息的文件的全路径(必须是已经存在的文件)
proj_id为任意低8位不为0的数(因为要取它的低8位)
ftok算法
返回值:成功返回一个key值 失败返回-1
2.#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
原型:int msgget(key_t key,int msgflg);
参数:key可由ftok获得
flag可取三个值 IPC_CREAT IPC_EXCL IPC_CREAT|IPC_EXCL
IPC_CREAT 创建一个消息队列并返回队列的标识,如果该队列已存在则直接返回该标识
IPC_EXCL 本身并没多大意思,通常和IPC_CREAT一起使用
IPC_CREAT|IPC_EXCL 创建消息队列,如果该队列已经存在则直接返回-1报错,保证资源是 新建的而不是打开的
返回值:成功返回队列标识 _msg_id 失败返回-1
3.#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
接收消息:ssize_t msgrcv(int msgid, const void *msgp,size_t msgsz,int msgtyp,int msgflg);
发送消息:int msgsnd(int msgid,const void *msgp,size_t msgsz,int msgflg));
参 数: msg_id为消息队列的标识, msgp为指向消息缓冲区的指针(用户可自己制定的通用结构)
msgsz为消息的大小,msftyp为从队列中取消息的类型,为0可以取任何消息,
msgflg指明当消息队列中没消息时应该做的指示,0为阻塞,IPC_NOWAIT则直接返回-1;
用到的命令:
ipcs -q //查看系统中存在的消息队列
ipcrm -q key值 //删除指定的key值的消息队列
//comm.h #ifndef _MSG_QUEUE_ #define _MSG_QUEUE_ #include<stdio.h> #include<sys/ipc.h> #include<sys/types.h> #include<stdlib.h> #include<sys/msg.h> #include<string.h> #define _PATH_ "/tmp/.msg" #define _PROJ_ID_ 0x55 #define _MSG_SIZE_ 1024 extern const long is_server_snd; extern const long is_client_snd; typedef struct _msg_info _msg_info; struct _msg_info { int mtype; char mtext[_MSG_SIZE_]; }; static int comm_msg(int flag); int creat_msg_queue(); int get_msg_queue(); int destroy(int msg_id); #endif
//comm.c #include"comm.h" const long is_server_snd=1; const long is_client_snd=2; static int comm_msg(int flag) { key_t _key=ftok(_PATH_,_PROJ_ID_); if(_key<0){ perror("ftok"); return -1; } int msg_id= msgget(_key,flag); if(msg_id<0){ perror("msgget"); return -1; } else return msg_id; } int creat_msg_queue() { return comm_msg(IPC_CREAT|IPC_EXCL); } int get_msg_queue() { return comm_msg(IPC_CREAT); } int destroy(int msg_id) { return msgctl(msg_id,IPC_RMID,NULL); }
//server.c #include"comm.h" int main() { int _msg_id=creat_msg_queue(); _msg_info msginfo; while(1){ msginfo.mtype=is_client_snd; memset(msginfo.mtext,‘\0‘,sizeof(msginfo.mtext)); if(msgrcv(_msg_id,&msginfo,sizeof(msginfo.mtext),is_client_snd,0)<0){ perror("msgrcv"); } else{ printf("client say# %s",msginfo.mtext); } msginfo.mtype=is_server_snd; memset(msginfo.mtext,‘\0‘,sizeof(msginfo.mtext)); read(0,msginfo.mtext,sizeof(msginfo.mtext)); if(msgsnd(_msg_id,&msginfo,sizeof(msginfo),0)<0){ perror("msgsnd"); } } if(destory(_msg_id)!=0){ perror("destory failed!\n"); } else printf("destory success!\n"); return 0; } //client.c #include"comm.h" int main() { int _msg_id= get_msg_queue(); _msg_info msginfo; while(1){ memset(msginfo.mtext,‘\0‘,sizeof(msginfo.mtext)); msginfo.mtype=is_client_snd; if(read(0,msginfo.mtext,sizeof(msginfo.mtext))>=0){ if(msgsnd(_msg_id,&msginfo,sizeof(msginfo.mtext),0)<0){ perror("msgsnd"); } } memset(msginfo.mtext,‘\0‘,sizeof(msginfo.mtext)); if(msgrcv(_msg_id,&msginfo,sizeof(msginfo),is_server_snd,0)<0){ perror("msgrcv"); } else{ printf("server say# %s",msginfo.mtext); } } return 0; } //Makefile .PHONY:all all:server client server:server.c comm.c gcc -o server server.c comm.c client:client.c comm.c gcc -o client client.c comm.c .PHONY:clean clean: rm -rf server client