Linux进程间通信之消息队列

Linux进程间通信之消息队列

一.消息队列
在这里插入图片描述
Msqid_ds 维护消息队列的结构体,队列的第一个消息指针msg_first,最后一个消息指针msg_last
消息中有一个成员指针next

每一个消息中包含有哪些内容:
Data 数据
Length 数据的长度
Type 数据的类型。
例如:
1----voltage data
2----电流数据
3----有功功率
与其他的不同的是内核空间创建的是一个链式队列
消息的接收端可以根据消息的类型来接收。
|文件I/O | 消息队列|
|open |msg_get|
|read| msgrcv|
|write| msgsnd|
|close| msgctrl |
Msgsnd相当于我们链式队列的插入操作,而msgrcv相当于我们链式队列的删除操作。

1. msgget创建或打开消息队列(open)
所需头文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型 int msgget(key_t key, int flag);
函数参数 key:和消息队列关联的key值
flag:消息队列的访问权限
函数返回值
成功:消息队列ID
出错:-1

2. msgsnd(write)
所需头文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型 int msgsnd(int msqid, const void *msgp, size_t size, int flag);
函数参数 msqid:消息队列的ID
msgp:指向消息的指针。常用消息结构msgbuf如下:
struct msgbuf
{
long mtype; //消息类型
char mtext[N] //消息正文
};
size:发送的消息正文的字节数,而不是整个结钩体的大小
flag: IPC_NOWAIT (非阻塞)消息没有发送完成函数也会立即返回。
0:(阻塞)直到发送完成函数才返回
函数返回值
成功:0
出错:-1

3.Msgrcv(read)
所需头文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型 int msgrcv(int msgid, void* msgp, size_t size, long msgtype, int flag);
函数参数 msqid:消息队列的ID(从哪里读)
msgp:接收消息的缓冲区
size:要接收的消息的字节数(想读多少个,一般也是正文的大小)
msgtype: 0:接收消息队列中第一个消息。
大于0:接收消息队列中第一个类型为msgtyp的消息.
小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型值又最小的消息。
flag: 0:若无消息函数会一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。
函数返回值
成功:接收到的消息的长度
出错:-1

消息队列中数据读后,数据也不存在了

4.Msgctl(close)
所需头文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型 int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
函数参数 msqid:消息队列的队列ID
cmd: IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。(如IPCS –q的作用)
IPC_SET:设置消息队列的属性。这个值取自buf参数。
IPC_RMID:从系统中删除消息队列。
buf:消息队列缓冲区
函数返回值
成功:0
出错:-1

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct msgbuf
{
  long type;
  char voltage[124];
  char ID[4];
};
int main()
{
  int msgid;
  int readret;
  struct msgbuf sendbuf,recvbuf;
  msgid=msgget(IPC_PRIVATE,0777);
  if(msgid <0)
  {
	printf("creat message queue failure\n");
	return -1;
  }
  printf("creat message queue  sucess msgid=%d\n",msgid);
  system("ipcs -q");
  //init sendbuf
  sendbuf.type=100;
  printf("please input message:\n");
  fgets(sendbuf.voltage,124,stdin);
  //start write message to message queue
  msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);

  //start read message from message queue
  memset(recvbuf.voltage,0,124);
  readret=msgrcv(msgid,(void *)&recvbuf,124,100,0);
  printf("recv:%s",recvbuf.voltage);
  printf("readret=%d\n",readret);
  //second read message queue
  msgrcv(msgid,(void *)&recvbuf,124,100,0);
  printf("second read after\n");
  //delete message queue
  msgctl(msgid,IPC_RMID,NULL);
  system("ipcs -q");
  return 0;
}

在这里插入图片描述
通过消息队列来实现两个非亲缘进程间的单向通信:
read.c

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct msgbuf
{
  long type;
  char voltage[124];
  char ID[4];
};
int main()
{
  int msgid;
  int readret;
  int key;
  struct msgbuf sendbuf,recvbuf;
  key=ftok("./a.c",'a');
  if(key < 0)
  {
	 printf("creat key failure\n");
	 return -2;
  }
  msgid=msgget(key,IPC_CREAT|0777);
  if(msgid <0)
  {
	printf("creat message queue failure\n");
	return -1;
  }
  printf("creat message queue  sucess msgid=%d\n",msgid);
  system("ipcs -q");
 
  //read message queue
  while(1)
  {
   memset(recvbuf.voltage,0,124);//clear receive buffer
   //start read message from message queue
   msgrcv(msgid,(void *)&recvbuf,124,100,0);
   printf("receive data from message queue:%s",recvbuf.voltage);
  }
  msgctl(msgid,IPC_RMID,NULL);
  system("ipcs -q");
  return 0;
}

write.c

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct msgbuf
{
  long type;
  char voltage[124];
  char ID[4];
};
int main()
{
  int msgid;
  int readret;
  int key;
  struct msgbuf sendbuf,recvbuf;
  key=ftok("./a.c",'a');
  if(key < 0)
  {
	 printf("creat key failure\n");
	 return -2;
  }
  msgid=msgget(key,IPC_CREAT|0777);
  if(msgid <0)
  {
	printf("creat message queue failure\n");
	return -1;
  }
  printf("creat message queue  sucess msgid=%d\n",msgid);
  system("ipcs -q");
  sendbuf.type=100; 
  //write message queue
  while(1)
  {
   memset(sendbuf.voltage,0,124);//clear send buffer
   printf("please input message:\n");
   fgets(sendbuf.voltage,124,stdin);
   //start write message to message queue
   msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
  }
  msgctl(msgid,IPC_RMID,NULL);
  system("ipcs -q");
  return 0;
}

在这里插入图片描述
在这里插入图片描述
特点:1.消息队列中的数据读完就删除了。
2.可以用阻塞的方式来接受数据。
实现双向通信:(同时收发)

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct msgbuf
{
  long type;
  char voltage[124];
  char ID[4];
};
int main()
{
  int msgid;
  int readret;
  int key;
  int pid;
  struct msgbuf sendbuf,recvbuf;
  key=ftok("./a.c",'a');
  if(key < 0)
  {
	 printf("creat key failure\n");
	 return -2;
  }
  msgid=msgget(key,IPC_CREAT|0777);
  if(msgid <0)
  {
	printf("creat message queue failure\n");
	return -1;
  }
  printf("creat message queue  sucess msgid=%d\n",msgid);
  system("ipcs -q");
  
  pid=fork();
  if(pid == 0) //child process   write 200
  {
   sendbuf.type=200; 
   //write message queue
   while(1)
   {
    memset(sendbuf.voltage,0,124);//clear send buffer
    printf("please input message:\n");
    fgets(sendbuf.voltage,124,stdin);
    //start write message to message queue
    msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
   }
  }
  if(pid > 0)//parent  process read 100
  {
	while(1)
	{
	 memset(recvbuf.voltage,0,124);
	 msgrcv(msgid,(void *)&recvbuf,124,100,0);
	 printf("receive message from message queue:%s",recvbuf.voltage);
	}
  }
  msgctl(msgid,IPC_RMID,NULL);
  system("ipcs -q");
  return 0;
}

server.c

#include "sys/types.h"
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct msgbuf
{
  long type;
  char voltage[124];
  char ID[4];
};
int main()
{
  int msgid;
  int readret;
  int key;
  int pid;
  struct msgbuf sendbuf,recvbuf;
  key=ftok("./a.c",'a');
  if(key < 0)
  {
	 printf("creat key failure\n");
	 return -2;
  }
  msgid=msgget(key,IPC_CREAT|0777);
  if(msgid <0)
  {
	printf("creat message queue failure\n");
	return -1;
  }
  printf("creat message queue  sucess msgid=%d\n",msgid);
  system("ipcs -q");
  
  pid=fork();
  if(pid > 0) //parent process   write 100
  {
   sendbuf.type=100; 
   //write message queue
   while(1)
   {
    memset(sendbuf.voltage,0,124);//clear send buffer
    printf("please input message:\n");
    fgets(sendbuf.voltage,124,stdin);
    //start write message to message queue
    msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
   }
  }
  if(pid == 0)//child process read 200
  {
	while(1)
	{
	 memset(recvbuf.voltage,0,124);
	 msgrcv(msgid,(void *)&recvbuf,124,200,0);
	 printf("receive message from message queue:%s",recvbuf.voltage);
	}
  }
  msgctl(msgid,IPC_RMID,NULL);
  system("ipcs -q");
  return 0;
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值