APUE学习之----进程通信实现消息队列

1.代码实现

实现两个程序之间通信,一个负责接收数据,并根据消息的不同类型输出不同的描述信息。另一个负责接收数据,发送了从标准输入的三种不同消息。一个头文件定义两个程序都需要的定义,最后用makefile文件编译得到两个输出文件。

头文件定义:

#define TOKPATH "/tmp/path.c"
#define TOKID 'm'

#define MSGLEN 512
#define MEGTYPE_1 1
#define MEGTYPE_2 2
#define MEGTYPE_3 3
struct msg_strc{
	long mtype;
	char mtext[MSGLEN];
};
接收函数:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include "proto.h"

int main(int argc,char *argv[])
{
	key_t key;
	struct msg_strc recbuf;
	int msgid;
	int data_type;
	if((key=ftok(TOKPATH,TOKID))< 0){
		perror("ftok()");
		exit(1);
	}
	if((msgid=msgget(key,IPC_CREAT|0644))< 0){
		perror("msgget()");
		exit(1);
	}
	for(;;){
		data_type=0;//0 recieve all types;can replace with 1,2,3
		if((msgrcv(msgid,&recbuf,sizeof(recbuf)-sizeof(long),data_type,0))< 0){
			perror("msgrcv()");
			exit(1);
		}
		if(recbuf.mtype==1){
			printf("This is a user name:%s\n",recbuf.mtext);
		}
		else if(recbuf.mtype==2){
			printf("This is a user passwd:%s\n",recbuf.mtext);
		}
		else if(recbuf.mtype==3){
			printf("This is a user describe:%s\n",recbuf.mtext);
		}
		
	}
	if((msgctl(msgid,IPC_RMID,0))< 0){
		perror("msgctl()");
		exit(1);
	}
	exit(0);
}

发送函数:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include "proto.h"

int main(int argc,char *argv[])
{
	key_t key;
	int msgid;
	int data_type;
	char buf[BUFSIZ];
	struct msg_strc sndbuf;
	if((key=ftok(TOKPATH,TOKID))< 0){
		perror("ftok()");
		exit(1);
	}
	if((msgid=msgget(key,0))<0){
		perror("msgget()");
		exit(1);
	}
	for(int i=1;i<4;++i){
		data_type=i;
		fgets(buf,BUFSIZ,stdin);
		sndbuf.mtype=data_type;
		strcpy(sndbuf.mtext,buf);
		if((msgsnd(msgid,&sndbuf,sizeof(sndbuf)-sizeof(long),0))<0){
			perror("msgsnd()");
			exit(1);
		}
	}
	exit(0);
}

makefile:

CFLAGS= -Wall -std=gnu99  
objects=megsnd megrec
all:megsnd megrec
.PHONY : all
megsnd : megsnd.o
	cc $(CFLAGS)  -o megsnd megsnd.o
megrec : megrec.o
	cc $(CFLAGS)  -o megrec megrec.o
megsnd.o :megsnd.c proto.h
	cc $(CFLAGS)  -o megsnd.o -c megsnd.c
megrec.o :megrec.c proto.h 
	cc $(CFLAGS)  -o megrec.o -c megrec.c

clean :
	rm $(objects) *.o

运行结果:

bash-4.2$ ./megsnd 
jack
19910125
I'am a programmer
bash-4.2$ ./megrec 
This is a user name:jack

This is a user passwd:19910125

This is a user describe:I'am a programmer

在上面的makefile中,实现不够简介,下一步可以花时间来仔细学习下。


2.消息队列介绍
一个或多个进程可向消息队列写入消息,而一个或多个进程可从消息队列中读取消息,这种进程间通讯机制通常使用在客户/服务器模型中,客户向服务器发送请求消息,服务器读取消息并执行相应请求。在许多微内核结构的操作系统中,内核和各组件之间的基本通讯方式就是消息队列。

Linux中的消息可以被描述成在内核地址空间的一个内部链表,每一个消息队列由一个IPC的标识号唯一的标识。Linux 为系统中所有的消息队列维护一个 msgque 链表,该链表中的每个指针指向一个 msgid_ds 结构,该结构完整描述一个消息队列。

1.1创建函数

#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>  
int msgget(key_t key, int msgflg);

msgget 函数的作用是创建一个消息队列,消息读列是双工的,两边都可以读写。

参数列表:

  key 通信的键值,拥有相同 key 的双方才可以通信。

  key 值必须是唯一的,系统中有个 ftok(3) 函数可以用于获取 key,通过文件 inode 和 salt 进行 hash 运算来生成唯一的 key,只要两个进程使用相同的文件和 salt 就可以生成一样的 key 值了。

  msgflg:特殊要求。无论有多少特殊要求,只要使用了 IPC_CREAT,就必须按位或一个权限。

同一个消息队列只需要创建一次,所以谁先运行起来谁有责任创建消息队列,后运行起来的就不需要创建了。

同理,对于后启动的进程来说,消息队列不是它创建的,那么它也没有必要销毁了。

1.2发送和接收函数

#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>  
int msgget(key_t key, int msgflg);
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);
struct msgbuf {
long mtype;
char mtext[1];  
};
msgrcv 函数从 msgid 这个消息队列中接收数据,并将接收到的数据放到 msgp 结构体中,这段空间有 msgz 个字节大小,msgz 的值要减掉强制的成员 mtype 的大小(sizeof(long))。

msgtyp 是 msgp 结构体中的 mtype 成员,表示要接收哪种类型的消息。虽然 msg 是消息队列,但是它并不完全遵循队列的形式,可以让接收者挑消息接收。如果不挑消息可以填写 0,这样就按照队列中的消息顺序返回。msfglg 是特殊要求位图,没有写0。

msgsnd函数向 msgid 这个消息队列发送 msgp 结构体数据,msgp 的大小是 msgsz,msgflg 是特殊要求,没有特殊要求可以写 0。 

1.3消息队列控制函数

#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>   
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

通过 cmd 指定具体的命令,然后通过 buf 为 cmd 命令设定参数,当然有些命令是需要参数的,有些命令则不需要参数。

最常用的 cmd 就是 IPC_RMID,表示删除(结束)某个 IPC 通信,并且这个命令不需要 buf 参数,直接传入 NULL 即可。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值