Linux IPC 进程间通信——消息队列message

        消息队列是消息的连接表,存储在内核中。本实例主要实现消息队列方式进行进程间通信,接收端收到消息之后,立马转发给发送端;发送端发出消息之后,立马监听接收端回馈的消息,实现一个双向通信示例。

一、示例

发送端client.c

#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <errno.h>  
#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>  
#include <sys/stat.h> 
#include <unistd.h>

#define MSG_FILE "server.c"  
#define BUFFER 255  
#define PERM S_IRUSR|S_IWUSR

struct msgtype {  
	long mtype;  
	char buffer[BUFFER];  
}; 

int main(int argc,char **argv)  
{  
	struct msgtype msg;  
	key_t key;  
	int msgid;
	struct msqid_ds msqid;


	if((key = ftok(MSG_FILE, 'a')) == -1) {  
		fprintf(stderr,"Creat Key Error:%s\a\n",strerror(errno));  
		exit(-1);  
	}

	if((msgid = msgget(key, PERM | IPC_CREAT))==-1)  
	{  
		fprintf(stderr,"Creat Message Error:%s\a\n",strerror(errno));  
		exit(-1);  
	}

	printf("PID=%d\n", getpid());

	while(1) {
		printf("Please in put the sending msg:");
		if((fgets(msg.buffer, BUFFER, stdin)) == NULL){
			printf("No message, terminal msg sending\n");
			exit(1);
		}
		msg.mtype=1;
		// client send.
		msgsnd(msgid, &msg, sizeof(struct msgtype), 0);

		memset(&msg,'\0',sizeof(struct msgtype));
		sleep(1);
		// client recive.
		msgrcv(msgid, &msg, sizeof(struct msgtype), 2, 0);
		fprintf(stderr,"Client receive:[ID=%ld] msg=%s\n", msg.mtype, msg.buffer);
		msgctl(msgid, IPC_STAT, &msqid);
		printf("last-msgsnd pid=%d\nlast-msgrcv pid=%d\n", msqid.msg_lspid, msqid.msg_lrpid);
	}

	// remove msg in system and delete all data in buffer.
	msgctl(msgid, IPC_RMID, NULL);
 
	exit(0);  
}

接收端Server.c

#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <errno.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/stat.h>  
#include <sys/msg.h>  

#define MSG_FILE "server.c"  
#define BUFFSIZE 255  
#define PERM S_IRUSR|S_IWUSR  

struct msgtype {  
	long mtype;  
	char buffer[BUFFSIZE];  
};


int main(void) {  
	struct msgtype msg;  
	key_t key;  
	int msgid;  

	if((key = ftok(MSG_FILE, 'a')) == -1) {  
		fprintf(stderr,"Creat Key Error %s\a\n",strerror(errno));  
		exit(-1);  
	}

	if((msgid = msgget(key, PERM|IPC_CREAT)) == -1) {  
		fprintf(stderr,"Creat Message Error:%s\a\n",strerror(errno));  
		exit(-1);  
	}  
	printf("PID=%d\n", getpid());
	while(1)
	{
		// server receive.
		msgrcv(msgid, &msg, sizeof(struct msgtype), 1, 0);  
		fprintf(stderr,"Server Receive:[ID=%ld] %s\n", msg.mtype, msg.buffer);
		msg.mtype = 2;
		// server send.
		printf("send:%s\n", msg.buffer);
		msgsnd(msgid, &msg, sizeof(struct msgtype), 0);
	}  
	exit(0);  
}

运行结果:

接收端

PID=141798
Server Receive:[ID=1] hello

send:hello

Server Receive:[ID=1] hello

send:hello

Server Receive:[ID=1] world

send:world

发送端

PID=141800
Please in put the sending msg:hello
Client receive:[ID=2] msg=hello

last-msgsnd pid=141798
 last-msgrcv pid=141800
Please in put the sending msg:world
Client receive:[ID=2] msg=world

last-msgsnd pid=141798
 last-msgrcv pid=141800

二、接口函数分析

key_t ftok(const char *path, int id);

        内核中IPC结构(消息队列、信号量、共享内存)都有一个唯一的非负整数标识符,都是通过ftok函数产生。Path,必须引用一个现有的文件,当产生key时,只使用id参数的低8位。

int msgget (key_t key, int msgflg);

        用于创建一个新队列或者打开一个现有队列,比如指定key为IPC_PRIVATE表示引用一个现有队列;而用ftok产生的key,表示创建一个新队列。msgflg有三个:
        IPC_CREAT(如果key不存在就创建);
        IPC_EXCL(如果key存在,返回失败);
        IPC_NOWAIT(返回错误不等待)

int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg);

        msqid表示msget返回的id值;msgp指针指向发送的自定义的数据buffer;msgsz,指定发送数据buffer的长度;msgflag可以指定为IPC_NOWAIT,表示如果队列已满,立即返回EAGAIN,如果没有指定IPC_NOWAIT,则会一直阻塞到:有空间可以容纳要发送的消息,或者从系统中删除了此队列(返回EIDRM错误),或者捕捉到一个信号并从信号处理程序返回(返回EINTR错误)。

ssize_t msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

        msqidmsgpmsgszmsgflag与上面msgsnd接口描述的一样,msgtyp指定了在msgflg指定的队列溢出或者下溢之后返回的消息值。msgtyp分类:
        msgtyp==0,返回队列中第一个消息;
        msgtyp>0,返回队列中消息类型为msgtyp的消息;
        msgtyp<0,返回队列中消息类型小于msgtyp绝对值的消息,如果消息有多个,则取类型值最小的那个。

int msgctl (int msqid, int cmd, struct msqid_ds *buf);        

        类似于ioctl函数,第一个参数msqid是msgget的返回值,第二个cmd有如下:
        IPC_SATA,获取队列的msqid_ds结构体信息,并存入buf中;
        IPC_SET,讲buf中相关msqid_ds相关数据设定到队列的msqid_ds中;
        IPC_RMID,从系统中删除该消息队列以及仍然在队列中的数据,删除立即生效,如果正在使用这个队列的进程当它再一次对队列进行操作时会返回EIDRM错误;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值