c++创建十个队列_Linux消息队列实验

消息队列,就是一些消息的列表,用户可以在消息队列中添加消息和读取消息等。消息队列用于运行于同一台机器上的进程间通信,与有名管道/FIFO很相似, 但是它可以实现消息的随机查询,比有名管道有更大的优势。同时,消息队列以消息链表的形式存在于系统内核中,由"队列ID"来标识。 我们可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向其中按照一定的规则添加新消息,对消息队列有读权限的进程则可以从消息队列中读走消息。

在Linux系统中消息队列的实现操作有:

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

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

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

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

1. 与消息队列相关的函数用法(1) msgget()函数功能:创建和访问一个消息队列,用法如下表所示。

19f3fb1d7626d0d963c85458e7d129a1.png

(2) msgsnd()函数 功能:把消息添加到消息队列中,用法如下表所示。

b3d48fc117e678fa088bc38998fc374e.png

3. msgrcv()函数

功能:从一个消息队列获取消息,用法如下表所示。

3b70f47436896f5348d916c338936fa3.png

4. msgctl()函数功能: 用来控制消息队列,它与共享内存的shmctl函数相似。用法如下表所示。

9e0692b6ef9b7b5487a52e8d290b6e15.png

2. 使用消息队列进行进程间通信 编写两个C源程序msgreceive.c和msgsned.c来接收和发送信息。正常的情况下,允许两个程序都可以创建消息,但只有接收者在接收完最后一个消息之后,它才将其删除。 msgreceive.c源程序如下。
#include #include 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", 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);}
msgsned.c源程序如下。
#include #include #include #include #include #include #define MAX_TEXT 512struct 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);}
编译运行,结果如下。

880ad0c8a44b61acdb49f80b547425a0.png

可以使用命令 ipcs -q可以查看当前系统的消息队列的信息。 源程序中的注意1:msgreceive.c文件main()函数中定义的变量msgtype作为msgrcv()函数的接收信息类型参数的值,其值为0,表示获取队列中第一个可用的消息。再来看看msgsend.c文件中while循环中的语句data.msg_type = 1(源程序中的注意2),它用来设置发送的信息的信息类型,即其发送的信息的类型为1。所以程序msgreceive.c能够接收到程序msgsend.c发送的信息。 如果把msgreceive.c文件main()函数中的语句由long int msgtype = 0;改变为long int msgtype = 2;会发生什么情况? msgreceive.c将不能接收到程序msgsend.c发送的信息。因为在调用msgrcv()函数时,如果msgtype(第四个参数)大于零,则将只获取具有相同消息类型的第一个消息,修改后获取的消息类型为2,而msgsend.c发送的消息类型为1,所以不能被msgreceive.c接收。重新编译msgreceive.c文件并再次执行,其结果如下:

3f6b6d500cbdf839eab52f48670f6f35.png

我们可以看到,msgr并没有接收到信息和输出,而且当msgsend输入end结束后,msgr也没有结束,通过ps -all命令我们可以看到它还在运行着。

6e7f7deaedf08544cbe303fb0b047498.png

消息队列跟有名管道有不少的相同之处,第一,它们都可以在互不相关的进程间实通信,同时它们都是通过发送和接收的方式来传递数据的。在有名管道中,发送数据用write(),接收数据用read(),在消息队列中,发送数据用msgsnd(),接收数据用msgrcv()。第二,它们对每个数据都有一个最大长度的限制。但 与有名管道相比,消息队列的优势在于:(1) 消息队列也可以独立于发送和接收进程而存在,从而消除了在同步 有名管道的打开和关闭时可能产生的困难。(2) 同时通过发送消息还可以避免 有名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。(3)接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。 参考[1] https://blog.csdn.net/mybelief321/article/details/9185625[2] https://www.cnblogs.com/52php/p/5862114.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值