Linux 进程间通信(七)消息队列

顾名思义, 消息队列就是一些消息的列表, 用户可以在消息队列中添加消息和读取消息等。从这点上看, 消息队列具有一定的 FIFO 特性, 但是它可以实现消息的随机查询, 比 FIFO具有更大的优势。 同时, 这些消息又是存在于内核中的, 由“队列 ID” 来标识。

消息队列的实现包括创建或打开消息队列、 添加消息、 读取消息和控制消息队列 4 种操作,

创建或打开消息队列使用的函数是 msgget(), 这里创建的消息队列的数量会受到系统消息队列数量的限制;

添加消息使用的函数是 msgsnd(), 它把消息添加到已打开的消息队列末尾;

读取消息使用的函数是 msgrcv(), 它把消息从消息队列中取走, 与 FIFO 不同的是,这里可以取走指定的某一条消息;

控制消息队列使用的函数是 msgctl(), 它可以完成多项功能。
 

msgget()函数的语法要点。
函数原型

int msgget(key_t key, int msgflg)
函数传入值
key: 消息队列的键值, 多个进程可以通过它访问同一个消息队列, 其中有个特殊值IPC_PRIVATE, 用于创建当前进程的私有消息队列
msgflg: 权限标志位
函数返回值
成功: 消息队列 ID
出错: 1

msgsnd()函数的语法要点。

函数原型

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
函数传入值
msqid: 消息队列的队列 ID
msgp: 指向消息结构的指针, 该消息结构 msgbuf 通常如下。

  • struct msgbuf
  •     long mtype; /* 消息类型, 该结构必须从这个域开始 */
  •     char mtext[1]; /* 消息正文 */

msgsz: 消息正文的字节数(不包括消息类型指针变量)
msgflg:

  1. IPC_NOWAIT: 若消息无法立即发送(如当前消息队列已满) , 函数会立即返回
  2. 0: msgsnd 调用阻塞直到发送成功为止

函数返回值
成功: 0
出错: 1

msgrcv()函数的语法要点。

函数原型

int msgrcv(int msgid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
函数传入值

msqid: 消息队列的队列 ID
msgp: 消息缓冲区, 同 msgsnd()函数的 msgp
msgsz: 消息正文的字节数(不包括消息类型指针变量)
msgtyp:

  1. 0: 接收消息队列中第一个消息
  2. 大于 0: 接收消息队列中第一个类型为 msgtyp 的消息续表
  3. 小于 0: 接收消息队列中第一个类型值不小于 msgtyp 绝对值且类型值最小的消息

msgflg:

  1. MSG_NOERROR:若返回的消息比 msgsz 字节多,则消息就会截短到 msgsz字节, 且不通知消息发送进程
  2. IPC_NOWAIT: 若在消息队列中并没有相应类型的消息可以接收, 则函数立即返回
  3. 0: msgsnd()调用阻塞直到接收一条相应类型的消息为止

函数返回值
成功: 0
出错: 1
 

重要结构体:

struct msqid_ds {
               struct ipc_perm msg_perm;     /* Ownership and permissions */
               time_t          msg_stime;    /* Time of last msgsnd(2) */
               time_t          msg_rtime;    /* Time of last msgrcv(2) */
               time_t          msg_ctime;    /* Time of last change */
               unsigned long   __msg_cbytes; /* Current number of bytes in
                                                queue (nonstandard) */
               msgqnum_t       msg_qnum;     /* Current number of messages
                                                in queue */
               msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                allowed in queue */
               pid_t           msg_lspid;    /* PID of last msgsnd(2) */
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };

//The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):

struct ipc_perm {
               key_t          __key;       /* Key supplied to msgget(2) */
               uid_t          uid;         /* Effective UID of owner */
               gid_t          gid;         /* Effective GID of owner */
               uid_t          cuid;        /* Effective UID of creator */
               gid_t          cgid;        /* Effective GID of creator */
               unsigned short mode;        /* Permissions */
               unsigned short __seq;       /* Sequence number */
           };

实例代码:

接收方

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
 
struct msg_st
{
	long int msg_type;
	char text[128];
};
 
int main()
{
	int running = 1;
	int msgid = -1;
	int len = 0;
	long int msgtype = 5; 
	struct msg_st data;
		
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
	if(-1 == msgid )
	{
		fprintf(stderr, "msgget failed with error: %d\n", errno);
		exit(EXIT_FAILURE);
	}
	
	while(running)
	{
		memset(&data.text, 0, 128);
		len = msgrcv(msgid, (void*)&data, 128, msgtype, 0);
		if(-1 == len)
		{
			fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
			exit(EXIT_FAILURE);
		}
		printf("You wrote: %s\n",data.text);
 
		if(0 == strncmp(data.text, "end", 3))
			running = 0;
	}
 
	//remove message queue
	if(-1 == msgctl(msgid, IPC_RMID, 0))
	{
		fprintf(stderr, "msgctl(IPC_RMID) failed\n");
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
}

发送方

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>
 
#define MAX_TEXT 512
struct msg_st
{
	long int msg_type;
	char text[MAX_TEXT];
};
 
int main()
{
	int running = 1;
	struct msg_st data;
	char buffer[BUFSIZ];
	int msgid = -1;
	int len;
 
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
	if(msgid == -1)
	{
		fprintf(stderr, "msgget failed with error: %d\n", errno);
		exit(EXIT_FAILURE);
	}
 
	while(running)
	{
		
		printf("Enter data : ");
		fgets(buffer, BUFSIZ, stdin);
		data.msg_type = 5;    
		strcpy(data.text, buffer);
	    len = strlen(data.text);	
		if(msgsnd(msgid, (void*)&data, len-1, 0) == -1)
		{
			fprintf(stderr, "msgsnd failed\n");
			exit(EXIT_FAILURE);
		}
		
		if(strncmp(buffer, "end", 3) == 0)
			running = 0;
		usleep(100000);
	}
	exit(EXIT_SUCCESS);
}

运行结果:

$ ./recv &
[1] 16437
$ ./send 
Enter data : 123
You wrote: 123
Enter data : 456
You wrote: 456
Enter data : 789
You wrote: 789
Enter data : end
You wrote: end
[1]+  Done                    ./recv

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值