IPC通信------IPC对象:1,共享内存,2,消息队列3,信号灯。
2,消息队列(链式队列)
msgget()创建函数的解析:
msgctl()释放函数的解析:
例子1:利用msgget()函数创建消息队列,再用msgctl()删除消息队列;创建creat_delete_massegeque.c,代码如下:
#include"unistd.h"
#include"sys/types.h"
#include"sys/msg.h"
#include"signal.h"
#include"stdio.h"
#include"stdlib.h"
int main()
{
int msgid;
//创建或打开消息队列
msgid=msgget(IPC_PRIVATE,0777);
if(msgid<0)
{
printf("creat message queue failure\n");
return -1;
}
printf("create message queue success\n");
system("ipcs -q");//查看消息队列属性
//删除消息队列
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
编译源文件,并运行./mque,结果如图:
可见,消息队列成功被创建后,又成功被删除了。
msgsnd()写入函数的解析:
例子2:基于例子1,在创建的消息队列里写入数据:
创建msgsnd.c文件,内容如下:
#include"unistd.h"
#include"sys/types.h"
#include"sys/msg.h"
#include"signal.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
//消息节点
typedef struct MsgNode{
long type;
char voltage[124];
char ID[4];
}MsgNode;
int main()
{
int msgid;
MsgNode snd;
//创建或打开消息队列
msgid=msgget(IPC_PRIVATE,0777);
if(msgid<0)
{
printf("creat message queue failure\n");
return -1;
}
printf("create message queue success\n");
system("ipcs -q");//查看消息队列属性
//向消息队列写入数据
fgets(snd.voltage,124,stdin);//从标准输入写入
msgsnd(msgid,(void*)&snd.voltage,strlen(snd.voltage),0);
system("ipcs -q");
while(1);
//删除消息队列
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
我们写入 :helloeveryone welcome to daily dictation共41个字符。运行结果如下图:
msgrcv读函数解析:
例子3:基于例子2,读出消息队列里的数据:
创建msgrcv.c文件,内容如下:
#include"unistd.h"
#include"sys/types.h"
#include"sys/msg.h"
#include"signal.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
//消息节点
typedef struct MsgNode{
long type;
char voltage[124];
char ID[4];
}MsgNode;
int main()
{
int msgid;
int readret;//读返回的字符个数
MsgNode snd;//写对象
MsgNode red;//读对象
//创建或打开消息队列
msgid=msgget(IPC_PRIVATE,0777);
if(msgid<0)
{
printf("creat message queue failure\n");
return -1;
}
printf("create message queue success\n");
system("ipcs -q");//查看消息队列属性
//init snd
snd.type=100;
//向消息队列写入数据
printf("please input message:\n");
fgets(snd.voltage,124,stdin);//从标准输入写入
msgsnd(msgid,(void*)&snd,strlen(snd.voltage),0);
//system("ipcs -q");
//clear voltage buf before read
memset(red.voltage,0,124);
//从消息队列里读数据
readret=msgrcv(msgid,(void*)&red,124,100,0);
printf("the result read from message queue\n");
printf("red.voltage=%sreadret=%d\n",red.voltage,readret);
//删除消息队列
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
写入之后hello linux!, 读出结果如下:
读出hello linux!。
【注意】对消息队列的读相当于对链表的删除,写相当于对消息队列的插入,所以读完队列里的消息就不在了。
综合实例:采用消息队列实现两个非亲缘关系进程A和B之间的双向通信;(多进程收发:主进程发,子进程收)。
【用来体现消息队列与管道通信和共享内存通信的区别和优点】
server的主进程写,子进程读;client的主进程读,子进程写。
建立server.c,client.c, a.c文件,如图:
server.c实现代码如下:
#include"unistd.h"
#include"sys/types.h"
#include"sys/msg.h"
#include"signal.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
//message node
typedef struct MsgNode{
long type;
char voltage[124];
char ID[4];
}MsgNode;
int main()
{
int msgid;
int readret;//return number of string
MsgNode sndbuf;//write object
MsgNode redbuf;//read object
int key;
key=ftok("./a.c",'a');//creat key for message queue
if(key<0)
{
printf("creat key failure\n");
return -1;
}
printf("creat key success, key=%d\n",key);
//creat or open message queue
msgid=msgget(key,IPC_CREAT | 0777);
if(msgid<0)
{
printf("creat message queue failure\n");
return -2;
}
printf("create message queue success\n");
system("ipcs -q");//check attributes of massege queues
pid_t pid;
pid=fork();//fork child process pid
if(pid>0)
{
//init sndbuf type
sndbuf.type =100;
while(1)
{
//clear sndbuf before write
memset(sndbuf.voltage,0,124);
//send message to client
printf("please send message to client:\n");
fgets(sndbuf.voltage,124,stdin);//write message from stdin to sndbuf
msgsnd(msgid,(void*)&sndbuf,strlen(sndbuf.voltage),0);//write message to msgque
}
}
//child process code
if(pid==0)
{
while(1)
{
//clear redbuf before read
memset(redbuf.voltage,0,124);
//read message from messageque
readret=msgrcv(msgid,(void*)&redbuf,124,200,0);
printf("\ncontent of message queue:\n");
printf("type = %ld\n",redbuf.type);
printf("red.voltage=%sreadret=%d\n",redbuf.voltage,readret);
}
}
//delete or free message queue
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
client.c实现代码如下:
#include"unistd.h"
#include"sys/types.h"
#include"sys/msg.h"
#include"signal.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
//message node
typedef struct MsgNode{
long type;
char voltage[124];
char ID[4];
}MsgNode;
int main()
{
int msgid;
int readret;//return number of message
MsgNode sndbuf;//writed object
MsgNode redbuf;//read object
int key;
key=ftok("./a.c",'a');//creat key
if(key<0)
{
printf("creat key failure\n");
return -1;
}
printf("creat key success, key=%d\n",key);
//creat or open message queue
msgid=msgget(key,IPC_CREAT | 0777);
if(msgid<0)
{
printf("creat message queue failure\n");
return -2;
}
printf("create message queue success\n");
system("ipcs -q");//check message attributes
pid_t pid;
pid=fork();//creat child process pid
//parent process code
if(pid>0)
{
while(1)
{
//clear redbuf before read message
memset(redbuf.voltage,0,124);
//read message from msgque
readret=msgrcv(msgid,(void*)&redbuf,124,100,0);
printf("message queue are:\n");
printf("red.voltage=%sreadret=%d\n",redbuf.voltage,readret);
}
}
if(pid==0)
{
//init type
sndbuf.type=200;
while(1)
{
//clear sndbuf before write
memset(sndbuf.voltage,0,124);
printf("please send message to server\n");
fgets(sndbuf.voltage,124,stdin);//write message from stdin
msgsnd(msgid,(void*)&sndbuf,strlen(sndbuf.voltage),0);//write to message queue
}
}
//delete message queue
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
以上是消息队列通信的总结。