利用消息队列发送数据
消息队列学习笔记,代码和理论均来自网络,如有侵权联系删除。另外本人小白一枚,欢迎各位大佬指点。
消息队列理论知识
消息队列是Linux系统进程之间通信一种方式,除此之外,进程通信方式还有多种。本文仅讨论消息队列通讯方式。消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
消息队列函数由msgget、msgctl、msgsnd、msgrcv四个函数组成。
具体函数参照及原型请参照下面博客介绍:
链接: https://blog.csdn.net/guoping16/article/details/6584024
下面是实际代码案例,相关的函数我会在代码下进行解释,适合小白观看,大神勿喷;
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.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 argc, char **argv)
{
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
// 建立消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1)
{
fprintf(stderr, "msgget failed error: %d\n", errno);
exit(EXIT_FAILURE);
}
// 向消息队里中写消息,直到写入end
while (1)
{
printf("Enter some text: \n");
fgets(buffer, BUFSIZ, stdin);
data.msg_type = 1; // 注意2
strcpy(data.text, buffer);
// 向队列里发送数据
if (msgsnd(msgid, (void *)&data, MAX_TEXT, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
// 输入end结束输入
if (strncmp(buffer, "end", 3) == 0)
{
break;
}
sleep(1);
}
exit(EXIT_SUCCESS);
}
分享一下我第一次看此代码不懂并且查找资料后的成果:
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
根据上文链接中的理论可知,(key_t)1234是将1234类型强转为key_t型,并且0666的相关含义查找资料后得知:从左向右:
第一位:表示这是个八进制数 000
第二位:当前用户的经权限:6=110(二进制),每一位分别对就 可读,可写,可执行,6说明当前用户可读可写不可执行
第三位:group组用户,6的意义同上
第四位:其它用户,每一位的意义同上,0表示不可读不可写也不可执行
fgets(buffer, BUFSIZ, stdin);
fgets函数语法(来自百度百科)
函数原型
char *fgets(char *str, int n, FILE *stream);
参数
str-- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
n-- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
stream-- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。
stdin函数语法(来自百度百科)
stdin; 从输入流stdin即输入缓冲区中读取7个字符到字符数组str中
参考网上的代码可以对此函数有更好的理解
# include <stdio.h>
int main(void)
{
char str[20]; /*定义一个最大长度为19, 末尾是'\0'的字符数组来存储字符串*/
printf("请输入一个字符串:");
fgets(str, 7, stdin); /*从输入流stdin即输入缓冲区中读取7个字符到字符数组str中*/
printf("%s\n", str);
return 0;
}
最后就是最重要的msgsnd函数本体了
msgsnd(msgid, (void *)&data, MAX_TEXT, 0) ;
参照上述链接中理论可以很轻松看懂,此函数的实参和理论中的形参一一对应即可,不再赘述;
然后是接收端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>
struct msg_st
{
long int msg_type;
char text[BUFSIZ];
};
int main(int argc, char **argv)
{
int msgid = -1;
struct msg_st data;
long int msgtype = 0; // 注意1
// 建立消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1)
{
fprintf(stderr, "msgget failed width error: %d\n", errno);
exit(EXIT_FAILURE);
}
// 从队列中获取消息,直到遇到end消息为止
while (1)
{
if (msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1)
{
fprintf(stderr, "msgrcv failed width erro: %d", errno);
}
printf("You wrote: %s\n", data.text);
// 遇到end结束
if (strncmp(data.text, "end", 3) == 0)
{
break;
}
}
// 删除消息队列
if (msgctl(msgid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
}
exit(EXIT_SUCCESS);
}
代码解析大抵相同,都是按照函数原型赋予实参;
最后附上学习过程中搜索的一些文档链接供读者参考:
Linux进程间的通信方式和原理
链接: https://www.cnblogs.com/liugh-wait/p/8533003.html
消息队列内核结构和msgget、msgctl 函数
链接: https://www.cnblogs.com/alantu2018/p/8473070.html