进程通信之消息队列

目录
消息队列的概念
msgsend.c, msgreceive.c
输出
(一)消息队列的概念
定义:是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。有写权限的进程可以向消息队列中添加新消息;有读权限的进程则可以从消息队列中读走消息。消息本质上是一种数据结构。暂且这样,先要会用,会用了可以继续研究内部实现过程。用都不会用,太纠结实现原理,在有限时间内,是得不偿失的。

(二)通信流程
下面只对用到的函数参数分析及代码解析,最后给一个编程思路。
下面涉及两个文件,msgsend.c与msgreceive.c
基本函数:msgrcv(接收)、msgsnd(发送)、msgget(新建)、msgctl(删除)

msgsend.c
(1)新建消息队列

//创建消息队列–类比于open,其返回的标识id,用于msgrcv(接收)、msgsnd(发送)
int msgget(key_t key, int msgflg);
1
2
参数:
(1)key:消息队列关联的标识符,本质是整数,可以弄个整数强制转化下就可以了,如(key_t)1234
(2)msgflg:消息队列的建立标志和存取权限

IPC_CREAT:如果内核中没有此队列则创建它
当IPC_EXCL和IPC_CREAT一起使用时,如果队列已经存在,则失败
例如: 用msgget创建一个消息队列
msg = msgget((key_t)1234, 0777|IPC_CREAT); //IPC_CREAT没有就创建及存取权限s
if(msg == -1)
{
fprintf(stderr, “The filure code is %d!!!\n”,errno); //errno–number of last error
exit(EXIT_FAILURE);
}
1
2
3
4
5
6
(2)消息队列的发送

//消息队列的发送–类比于write
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
1
2
参数:

msqid : 消息队列的标识码(msgget返回的id)
msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个是字符数组), 这里是void,要强制转换下,最好这样。
//这个结构体要用户自己写一个,只要第一个参数值大于0,第二个是字符数组,都可以了,如:
#define BUF_TEXT 512
struct msg_st
{
long msg_type; //标志位
char msg_text[BUF_TEXT]; //发送数据缓冲区
};

1
2
3
4
5
6
7
8
msgsz : 消息的长短
msgflg: 标志位–如果为0,表示忽略该标志位
返回值–On success, zero is returned. On error, -1 is returned
在这里插入图片描述

//msgsend.c

#include <stdio.h>
#include <sys/stat.h>
//msgget
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
//exit头文件
#include <stdlib.h>
#include <unistd.h>
//errno头文件
#include <errno.h>
#include <string.h>

#define BUF_TEXT 512

/****************************************************************************************
** 消息队列
** msgget():创建消息队列–类比于open
** int msgget(key_t key, int msgflg);
** key:
** 消息队列关联的标识符
** msgflg:消息队列的建立标志和存取权限
** IPC_CREAT:如果内核中没有此队列则创建它
** 当IPC_EXCL和IPC_CREAT一起使用时,如果队列已经存在,则失败
** RETURN VALUE
** 执行成功则返回消息队列的标识符(a nonnegative integer-非负整数),否则返回-1
** 注意:
** key_t本质是整数,你自己弄个整数强制转化下就可以了,如(key_t)1234
** msgsnd():消息队列的发送–类比于write
** int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 这里是void
,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgflg: 标志位
** RETURN VALUE
** On success, zero is returned. On error, -1 is returned
** msgrcv():消息队列的接受–类比于read
** ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 这里是void
,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息
** msgtyp大于0,则返回其类型为mtype的第一个消息
** msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
** msgflg: 标志位,如果为0,表示忽略该标志位
** RETURN VALUE
** 成功返回数据长度,错误返回-1
** fgets():从指定流中读出size-1个字符,若读入新行,则存在buffer中,最后要以NULL结尾
** char *fgets(char *s, int size, FILE *stream);
** stream: 几种标准的流/文件句柄
** stpcpy(): 字符串的复制
** char *stpcpy(char *dest, const char *src);
** strncmp(): 字符串比较
** char *strncmp(char *dest, const char *src, size_t n);
****************************************************************************************/

//msgsnd/msgrcv 第二个参数
struct msg_st
{
long msg_type; //标志位
char msg_text[BUF_TEXT]; //发送数据缓冲区
};

int main(void)
{
struct msg_st data;
int msg = -1; //标识id
int running = 1;
char buffer[BUFSIZ]; //系统常量BUFSIZ是8192–定义在stdio.h中

msg = msgget((key_t)1234, 0777|IPC_CREAT);					//IPC_CREAT没有就创建及存取权限s
if(msg == -1)
{
	fprintf(stderr, "The filure code is %d!!!\n",errno);	//errno--number of last error
	exit(EXIT_FAILURE);
}

while(running)
{
	printf("Please enter data: \n");
	fgets(buffer, BUFSIZ, stdin);							// 标准输入向buffer获取BUFSIZ-1个字符
	data.msg_type = 1;										//标志置1,表示要通信了。其他数也可以
	stpcpy(data.msg_text, buffer);							//将buffer的数据复制到结构体的msg_text中
	
	if(msgsnd(msg, (void *)&data, BUF_TEXT, 0) == -1)		//发送数据到data结构体的数组中
	{
		fprintf(stderr, "magsnd error!!!\n");
		exit(EXIT_FAILURE);
	}
	if(strncmp(data.msg_text, "end", 3) == 0)				//判断字符串是否相等,自己弄个结束标志	
	{
		running = 0;										//推出while
	}
	sleep(1);
}
exit(EXIT_SUCCESS);	   

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
msgreceive.c
(1)新建消息队列
和msgsend.c一样,都需要打开同一个消息队列才可以通信。见上

(2)消息队列的接收

msgrcv():消息队列的接受–类比于read
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
1
2
msqid : 消息队列的标识码(msgget返回的id)
msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组), 这里是void,要强制转换下,最好这样。—也就是说在msgreceive.c中也要定义一样的结构体。
msgsz : 消息的长短
msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息,这里给0
msgtyp大于0,则返回其类型为mtype的第一个消息
msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
msgflg: 标志位–如果为0,表示忽略该标志位
(3)断开消息队列的连接

msgctl():消息队列的控制函数,里面有一项可以删除消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
1
2
msqid : 消息队列的标识码(msgget返回的id)
cmd : IPC_RMID: 立即断开连接
返回值 —On success, IPC_STAT, IPC_SET, and IPC_RMID return 0.On error, -1 is returned
//断开消息队列的连接
if(msgctl(msg, IPC_RMID, 0) == -1) //msgctl删除消息队列
{
fprintf(stderr, “magctl error code %d !!!\n”,errno);
exit(EXIT_FAILURE);
}
1
2
3
4
5
6
在这里插入图片描述

//msgreceive.c

#include <stdio.h>
#include <sys/stat.h>
//msgget
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
//exit头文件
#include <stdlib.h>
#include <unistd.h>
//errno头文件
#include <errno.h>
#include <string.h>

/****************************************************************************************
** 消息队列
** msgrcv():消息队列的接受–类比于read
** ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 这里是void
,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息,这里给0
** msgtyp大于0,则返回其类型为mtype的第一个消息
** msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
** msgflg: 标志位,如果为0,表示忽略该标志位
** RETURN VALUE
** On success, zero is returned. On error, -1 is returned
** msgctl():
** int msgctl(int msqid, int cmd, struct msqid_ds *buf);
** msqid : 消息队列的标识码(msgget返回的id)
** cmd :
** IPC_RMID: 立即断开连接
** RETURN VALUE
** On success, IPC_STAT, IPC_SET, and IPC_RMID return 0.On error, -1 is returned
** fgets():从指定流中读出size-1个字符,若读入新行,则存在buffer中,最后要以NULL结尾
** char *fgets(char *s, int size, FILE *stream);
** stream: 几种标准的流/文件句柄
** stpcpy(): 字符串的复制
** char *stpcpy(char *dest, const char *src);
** strncmp(): 字符串比较
** char *strncmp(char *dest, const char *src, size_t n);
****************************************************************************************/

//msgsnd/msgrcv 第二个参数
struct msg_st
{
long msg_type; //标志位
char msg_text[BUFSIZ]; //系统常量BUFSIZ是8192–定义在stdio.h中
};

int main(void)
{
struct msg_st data;
int msg = -1; //标识id
int running = 1;
char buffer[BUFSIZ];
long int msgtype = 0; //这里给0,返回队列的最早的一个消息

//打开消息队列
msg = msgget((key_t)1234, 0777|IPC_CREAT);								//IPC_CREAT没有就创建及存取权限s
if(msg == -1)
{
	fprintf(stderr, "The filure code is %d!!!\n",errno);				//errno--number of last error
	exit(EXIT_FAILURE);
}

//接受消息队列的数据---以end结束
while(running)
{
	if(msgrcv(msg, (void *)&data, BUFSIZ, msgtype, 0) == -1)			//将结构体中数据通过msgrcv接收  
	{
		fprintf(stderr, "magcve error code %d !!!\n",errno);
		exit(EXIT_FAILURE);
	}
	printf("You just wrote:\n%s\n",data.msg_text);
	
	if(strncmp(data.msg_text, "end", 3) == 0)							//以end结束	
	{
		running = 0;
	}
}

//断开消息队列的连接
if(msgctl(msg, IPC_RMID, 0) == -1)										//msgctl删除消息队列
{
	fprintf(stderr, "magctl error code %d !!!\n",errno);
	exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);	

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
(三)输出
在这里插入图片描述

最后:下面图大致概述了下
————————————————
版权声明:本文为CSDN博主「ve2102388688」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_39956356/article/details/86652957

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值