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 即可。