100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Linux IPC 进程间通信——消息队列message

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

时间:2023-02-24 22:36:45

相关推荐

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_IWUSRstruct 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_tftok(const char *path, int id);

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

intmsgget(key_t key, int msgflg);

用于创建一个新队列或者打开一个现有队列,比如指定key为IPC_PRIVATE表示引用一个现有队列;而用ftok产生的key,表示创建一个新队列。msgflg有三个:

IPC_CREAT(如果key不存在就创建);

IPC_EXCL(如果key存在,返回失败);

IPC_NOWAIT(返回错误不等待)

intmsgsnd(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_tmsgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msqidmsgpmsgszmsgflag与上面msgsnd接口描述的一样,msgtyp指定了在msgflg指定的队列溢出或者下溢之后返回的消息值。msgtyp分类:

msgtyp==0,返回队列中第一个消息;

msgtyp>0,返回队列中消息类型为msgtyp的消息;

msgtyp<0,返回队列中消息类型小于msgtyp绝对值的消息,如果消息有多个,则取类型值最小的那个。

intmsgctl(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错误;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。