消息缓冲是UNIX系统进程之间进行大量数据交换的机制之一。消息缓冲是基于消息队列的。发送进程将消息挂入接收进程的消息队列,接收进程从消息队列中接收消息。消息是指具有类型和数量的一个数据。消息分共有和私有的,如果消息为私有的,只能被创建消息队列的进程和其子进程访问;如果是公有的,可以被系统中知道消息队列名的所有进程访问。消息可以按类型访问,因此,不必按序访问。关于这方面的好多知识,我也不是特别了解,有需要的可以自行Google.
为了理解进程利用消息缓冲的通信过程,下面给出两个例子
一、创建一个私有消息队列,一个进程自己发送消息和接收消息。创建一个消息队列,之后将一个消息“hello,world”放入消息队列。在从消息队列进行接收,并打印出所接受的消息。
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#define _USE_GNU
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
struct msgbuf{
long mtype;
char mtext[500];
};
int main(int argc,char *argv[])
{
int queue_id;
struct msgbuf * msg,*recv_msg;
int rc;
int msgsz;
queue_id=msgget(IPC_PRIVATE,IPC_CREAT|0600);
if(queue_id==-1){
perror("main's msgget");
exit(1);
}
printf("the created message's id ='%d'.\n",queue_id);
//分配一个消息结构"Hello World!"
msg = (struct msgbuf *)malloc(sizeof(struct msgbuf)+strlen("hello,world"));
msg -> mtype = 1;//消息队列的索引赋值为1
strcpy(msg -> mtext,"hello world");//将字符串复制到消息体中
//发送消息
rc = msgsnd(queue_id,msg,strlen(msg -> mtext) + 1,0);
//这里的+1是指字符串的结束符
if(rc == -1){
perror("msgsnd");
exit(1);
}
else
printf("%d\n",rc);
free(msg);//释放消息占用的空间
printf("message is placed on message's queue\n");
//接收消息
recv_msg = (struct msgbuf *)malloc(sizeof(struct msgbuf)+strlen("hello world")+1);
msgsz = strlen(recv_msg -> mtext) + 1;
rc = msgrcv(queue_id,recv_msg,msgsz,0,0);
if(rc == -1){
perror("msgrcv");
exit(1);
}
printf("received message's mtype is'%ld';mtext if '%s' \n",recv_msg->mtype,recv_msg->mtext);
msgctl(queue_id,IPC_RMID,NULL);//删除消息队列
return 0;
}
二、创建一个公共消息队列,实现客户进程和服务者进程之间进行通信
客户进程向服务者进程发送消息,请求服务。服务者进程接受消息,完成客户的服务请求后,再将服务结果以消息方式发送给客户。其具体实现描述为:
①服务者进程用关键字SVKEY和标志IPC_CREAT调用magget()建立一个消息队列,得到队列的标识符msgid之后,用msgid调用msgrcv()接受类型为REQ的消息。
②客户进程用关键字SVKEY调用msgget()得到消息队列标识符msgid,之后用msgid调用msgsnd()将自己的pid发送到消息队列(SVKEY)中,表示其所请求的服务。然后调用msgrcv()等待服务结果消息的到来。
③服务者进程接收到请求服务的消息后进行服务工作,完成服务后向客户进程发回一条消息,消息的类型为客户的标识pid,消息正文是服务者进程自己的标志pid,
④客户进程收到服务结果消息后,显示必要消息后,结束两者的通信过程。
客户进程的通信过程
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define SVKEY 75
#define REQ 1
struct msgform{
long mtype;//消息类型
char mtext[256];//消息正文
};
int main()
{
struct msgform msg;
int msgid;
int pid;
int *pint;
msgid = msgget(SVKEY,0777);
pid = getpid();//获得当前进程标识
pint = (int *)msg.mtext;//取消息正文的首地址
*pint = pid;//将客户进程的pid复制到消息缓冲区
msg.mtype = REQ;
msgsnd(msgid,&msg,sizeof(int),0);
msgrcv(msgid,&msg,256,pid,0);//这里的pid作为消息类型
printf("client receive server's service result is server's pid :%d.\n",*pint);
return 0;
}
服务者进程的通信过程
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define SVKEY 75
#define REQ 1
struct msgform{
long mtype;
char mtext[256];
};
int main()
{
struct msgform msg;
int i;
int msgid;
int pid;
int *pint;
msgid = msgget(SVKEY,0777|IPC_CREAT);
for(;;)
{
msgrcv(msgid,&msg,256,REQ,0);
printf("server is doing the service for a client.\n");
pint = (int *)msg.mtext;
pid = *pint;//获得客户进程的pid,以便进行服务
printf("server receive client's service request is client's pid:%d.\n",pid);
msg.mtype = pid;
*pint = getpid();
//将服务者服务结果的pid发送给客户
msgsnd(msgid,&msg,sizeof(int),0);
}
return 0;
}