Linux进程间通信–消息队列
消息队列提供了一种从一个进程向另一个进程发送数据块的方法。
每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。
消息队列与命名管道有一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数(MSGMNB)、系统上消息队列的总数也都有上限(MSGMNI)。
消息队列相关函数
- int msgget(key_t key, int msgflg);用来创建或访问消息队列
- int msgctl(int msqid, int cmd, struct msqid_ds *buf);消息队列的控制函数
- int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);把一条消息添加到消息队列中
- ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);从消息队列拿消息
参数含义
key | 消息队列的名称 |
---|---|
msgflg | 由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的 |
msgid | 由msgget函数返回的消息队列标识符 |
cmd | 是将要采取的动作,包括 IPC_STAT , IPC_SET , IPC_RMID |
msgp | 是一个指针,此位置用来暂时存储发送和接收的消息,是一个⽤用户可 定义的通用结构 |
msgsz | 是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型 |
msgtyp | 从消息队列内读取的消息形态。如果值为零,则表示消息队列中的所有消息都会被读取 |
接下来,我们利用上面的函数实现一个client/server通信的例子
Makefile
.PHONY:all
all:client server
client:client.c comm.c
gcc -o $@ $^
server:server.c comm.c
gcc -o $@ $^
.PHONY:clean
rm -f client server
comm.h
1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/ipc.h>
6 #include <sys/types.h>
7 #include <sys/msg.h>
8 #include <string.h>
9
10 struct msgbuf
11 {
12 long mtype;
13 char mtext[1024];
14 };
15
16 #define CLIENT_TYPE 1
17 #define SERVER_TYPE 2
18
19 int CreatMsg();
20 int GetMsg();
21 int DestoryMsg(int msgid );
22 int SendMsg(int msgid,long sndtype,char* msg);
23 int RecvMsg(int msgid,int rcvtype,char* buf);
comm.c
1 #include "comm.h"
2
3 static int Msg(int flag)
4 {
5 key_t key=ftok(".",0x6666);
6 if(key<0)
7 {
8 perror("key" );
9 return -1;
10 }
11 int msqid=msgget(key,flag);
12 if(msqid<-1)
13 {
14 perror("msgget" );
15 return -2;
16 }
17 return msqid;
18 }
19 int CreatMsg()
20 {
21 return Msg(IPC_CREAT|IPC_EXCL|0666);
22 }
23 int GetMsg()
24 {
25 return Msg(IPC_CREAT);
26 }
27 int DestoryMsg(int msqid )
28 {
29 if(msgctl(msqid,IPC_RMID,NULL)<0)
30 {
31 perror("msgctl" );
32 return -1;
33 }
34 return 0;
35
36 }
37 int SendMsg(int msqid,long sndtype,char* msg)
38 {
39 struct msgbuf buf;
40 buf.mtype=sndtype;
41 strcpy(buf.mtext,msg);
42 if(msgsnd(msqid,(void*)&buf,sizeof(buf.mtext),0)<0)
43 {
44 perror(" msgsnd" );
45 return -1;
46 }
47 return 0;
48 }
49 int RecvMsg(int msqid,int rcvtype,char* buf)
50 {
51 struct msgbuf buff;
52 int n=msgrcv(msqid,(void*)&buff,sizeof(buff.mtext),rcvtype,0);
53 if(n<0)
54 {
55 perror("msgrcv" );
56 return -1;
57 }
58 strncpy(buf,buff.mtext,n);
59 return 0;
60 }
server.c
1 #include "comm.h"
2
3 int main()
4 {
5 int msqid=CreatMsg();
6 char buf[1024];
7 while(1)
8 {
9 buf[0]=0;
10 RecvMsg(msqid,CLIENT_TYPE,buf);
11 printf("client say :%s\n" ,buf);
12 printf("Please Enter:" );
13 fflush(stdout);
14 ssize_t s=read(0,buf,sizeof(buf));
15 if(s>0)
16 {
17 buf[s-1]=0;
18 SendMsg(msqid,SERVER_TYPE,buf);//发送消息
19 }
20 }
21 DestoryMsg(msqid);
22 return 0;
23 }
client.c
1 #include "comm.h"
2
3 int main()
4 {
5 int msqid=GetMsg();
6 char buf[1024];
7 while(1)
8 {
9 buf[0]=0;
10 printf("Please Enter:" );
11 fflush(stdout);
12 ssize_t s = read(0,buf,sizeof(buf));
13 if(s<0)
14 {
15 perror("read" );
16 return -1;
17 }
18 if(s>0)
19 {
20 buf[s-1]=0;
21 SendMsg(msqid,CLIENT_TYPE,buf);
22 }
23 RecvMsg(msqid,SERVER_TYPE,buf);
24 printf("server say:%s\n" ,buf);
25 }
26 return 0;
27 }
运行结果如图