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

来源:互联网 发布:暗黑破坏神2 mac 1.13 编辑:程序博客网 时间:2024/06/16 20:40

1.代码实现

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

头文件定义:

#define TOKPATH "/tmp/path.c"#define TOKID 'm'#define MSGLEN 512#define MEGTYPE_1 1#define MEGTYPE_2 2#define MEGTYPE_3 3struct 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,3if((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 megrecall:megsnd megrec.PHONY : allmegsnd : megsnd.occ $(CFLAGS)  -o megsnd megsnd.omegrec : megrec.occ $(CFLAGS)  -o megrec megrec.omegsnd.o :megsnd.c proto.hcc $(CFLAGS)  -o megsnd.o -c megsnd.cmegrec.o :megrec.c proto.h cc $(CFLAGS)  -o megrec.o -c megrec.cclean :rm $(objects) *.o

运行结果:

bash-4.2$ ./megsnd jack19910125I'am a programmer
bash-4.2$ ./megrec This is a user name:jackThis is a user passwd:19910125This 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 即可。










0 0
原创粉丝点击