标签:
我会用几篇博客总结一下在Linux中进程之间通信的几种方法,我会把这个开头的摘要部分在这个系列的每篇博客中都打出来
进程之间通信的方式
这次主要写的是消息队列,之前讲过的管道和消息队列在本质上就有很大的区别,管道是一个文件,而消息队列是一个数据结构(类似于链表)。这说明了,管道文件是存放在磁盘上的,关机也会存在(尤其是命名管道更为显而易见,你不删除他他就搁那呆着),而消息队列是存在于内核中的内存,显而易见,关机就没了。
更关键的是,内存他快呀,比磁盘I/O快多了,为啥要用那么慢的管道。而且消息队列是可以直接完成没有亲缘关系的进程之间的通信的。但是结构比起管道要复杂,用到了很多结构体。内容有些多。先写一下和管道的主要区别,可以更直观的进行对比
那么从头开始吧:
在C库函数中有一个系统调用可以创建一个消息队列,那就是msgget,跟这个函数有关的其他函数也会一并给出来
相关函数就这么多,到这里就可以开心的创建一个新的消息队列了,那么怎么看我们创建出来的消息队列呢?怎么销毁他呢?
先用命令看一下,使用ipcs -q就可查看消息队列的状态,这里我创建了一个消息队列,下面来销毁它
使用ipcrm -q msqid就可以销毁一个消息队列,我已经把刚才创建的消息队列销毁了
那么如何通过C函数销毁一个消息队列?使用msgctl函数
这里提一下,消息队列的一个缺点,这里说到IPC_SET对消息队列的初始化,就是说消息队列的创建和初始化是分开的,这样设计不是很好,因为有线程安全的问题,当一个线程创建了消息队列还没初始化,另一个线程直接开始执行访问的操作就很尴尬了
1 struct msginfo {
2 int msgpool; /* Size in kibibytes of buffer pool
3 used to hold message data;
4 unused within kernel */
5 int msgmap; /* Maximum number of entries in message
6 map; unused within kernel */
7 int msgmax; /* Maximum number of bytes that can be
8 written in a single message */
9 int msgmnb; /* Maximum number of bytes that can be
10 written to queue; used to initialize
11 msg_qbytes during queue creation
12 (msgget(2)) */
13 int msgmni; /* Maximum number of message queues */
14 int msgssz; /* Message segment size;
15 unused within kernel */
16 int msgtql; /* Maximum number of messages on all queues
17 in system; unused within kernel */
18 unsigned short int msgseg;
19 /* Maximum number of segments;
20 unused within kernel */
21 };
提到使用消息队列无非就是消息的写入和消息的读出,这涉及两个函数和一个结构体
先说发送函数
在列接受函数之前必须把结构体放出来,不然下面就懵逼了
1 struct msgbuf {
2 long mtype; /* message type, must be > 0 */
3 char mtext[1]; /* message data */
4 };
从mtype讲起,因为队列是好多进程(或者说是线程)都拿来用的,比如4个进程共用一个消息队列,两两之间进行通信,就有必要标识哪两个进程是一组的,哪块数据是属于你们组的,不能乱拿是不是,这个mtype就是用来标识的,但是一定要大于0,我一开始设置为0一直报参数错误,查了文档才发现自己蠢了。。。
mtext存放的就是你要传输的数据了,怎么大小只有1?当然不能只有1,我自己写的msgbuf就有1024长度。。。所以还是自己写爽啊
可以说接受函数了
事已至此,基本操作就说完了,废话少说,show me the code
我的程序分为comm.h(公共头文件) comm.c(封装基本函数) server.c(建议服务器端) client.c(简易客户端)一共4个文件
完成了服务器端和客户端的简单通信(回合制聊天(误))
comm.h
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/msg.h>
4 #include <sys/types.h>
5 #include <sys/ipc.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <memory.h>
10
11
12 #define _PATH_NAME_ "/tmp"
13 #define _PROJ_ID_ 0x666
14 #define _SIZE_ 1024
15
16 static int comm_create_msg_set(int flags);
17 int create_msg_set();
18 int get_msg_set();
19 void destory_msg_set(int msg_id);
20 void send_msg(int msg_id,long msgtype,char * buf);
21 void receive_msg(int msg_id,long msgtype,char *buf);
22
23
24
25 struct msgbuf
26 {
27 long mtype;
28 char mtext[_SIZE_];
29 };
comm.c
1 #include "comm.h"
2 static int comm_create_msg_set(int flags)
3 {
4 key_t _key=ftok(_PATH_NAME_,_PROJ_ID_);
5 if(_key<0)
6 {
7 printf("%d:%s",errno,strerror(errno));
8 }
9 int msg_id=msgget(_key,flags);
10 if(msg_id<0)
11 {
12 printf("%d:%s",errno,strerror(errno));
13 }
14 return msg_id;
15 }
16
17
18 int get_msg_set()
19 {
20 key_t _key=ftok(_PATH_NAME_,_PROJ_ID_);
21 int flags=IPC_CREAT;
22 return comm_create_msg_set(flags);
23 }
24
25
26 int create_msg_set()
27 {
28 key_t _key=ftok(_PATH_NAME_,_PROJ_ID_);
29 int flags=IPC_CREAT | IPC_EXCL;
30 return comm_create_msg_set(flags);
31 }
32
33
34 void send_msg(int msg_id,long msgtype,char *buf)
35 {
36 memset(buf,‘\0‘,strlen(buf)+1);
37 ssize_t _size=read(0,buf,_SIZE_);
38 if(_size>0)
39 {
40 buf[_size-1]=‘\0‘;
41 }
42
43 struct msgbuf _mbuf;
44 memset(&_mbuf,‘\0‘,sizeof(struct msgbuf));
45 _mbuf.mtype=msgtype;
46 strcpy(_mbuf.mtext,buf);
47 if(msgsnd(msg_id,&_mbuf,_size,0)<0)
48 {
49 printf("send error,%d:%s",errno,strerror(errno));
50 }
51 }
52
53 void receive_msg(int msg_id , long msgtype ,char *buf)
54 {
55 struct msgbuf _mbuf;
56 memset(&_mbuf,‘\0‘,sizeof(struct msgbuf));
57 _mbuf.mtype=0;
58 if(msgrcv(msg_id,&_mbuf,_SIZE_,msgtype,0)<0)
59 {
60 printf("recv error %d:%s",errno,strerror(errno));
61 }
62 strcpy(buf,_mbuf.mtext);
63 }
64
65 void destory_msg_set(int msg_id)
66 {
67 if(msgctl(msg_id,IPC_RMID,0)<0)
68 {
69 printf("%d:%s",errno,strerror(errno));
70 }
71 }
server.c
1 #include "comm.h"
2 long c_type=1;
3 long s_type=22;
4 int main()
5 {
6 int msg_id=create_msg_set();
7 char buf[_SIZE_];
8
9 while(1)
10 {
11 memset(buf,‘\0‘,sizeof(buf));
12 receive_msg(msg_id,c_type,buf);
13 if(strcasecmp(buf,"quit")==0)
14 {
15 break;
16 }
17 printf("client # %s\n",buf);
18 printf("clent say done ! Please Input:");
19 fflush(stdout);
20 memset(buf,‘\0‘,sizeof(buf));
21 send_msg(msg_id,c_type,buf);
22 }
23 destory_msg_set(msg_id);
24 return 0;
25 }
client.c
1 #include "comm.h"
2
3
4 long c_type=1;
5 long s_type=2;
6
7 int main()
8 {
9 int msg_id = get_msg_set();
10
11 char buf[_SIZE_];
12
13 while(1)
14 {
15 memset(buf,‘\0‘,sizeof(buf));
16 send_msg(msg_id,c_type,buf);
17 if(strcasecmp(buf,"quit")==0)
18 {
19 break;
20 }
21 memset(buf,‘\0‘,sizeof(buf));
22 receive_msg(msg_id,c_type,buf);
23 printf("server # %s\n",buf);
24 printf("server say done ! Please Input:");
25 fflush(stdout);
26 }
27
28 return 0;
29 }
标签:
原文地址:http://www.cnblogs.com/lenomirei/p/5642575.html