Linux进程间通信之消息队列

  • 一 消息队列概述
  • 二 消息队列的特点
  • 三 消息队列的创建和使用
    • 3.1 获取系统唯一的key值
    • 3.2 创建消息队列
    • 3.3 查看消息队列和删除消息队列的shell命令
    • 3.4 消息队列的信息格式的定义
    • 3.5 发送消息函数msgsnd
    • 3.6 接收消息函数msgrcv
    • 3.7 总结
    • 3.8 消息队列的控制
  • 四 消息队列练习题:实现多人聊天程序

一 消息队列概述

消息队列是消息的链表,存放在内存中,由内核维护;

二 消息队列的特点

1. 消息队列中的消息是有类型的;
2. 消息队列中的消息是有格式的;
3. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,编程时可以按消息的类型读取;
4. 消息队列允许一个或多个进程向它写入或读取消息;
5. 与无名管道、命名管道一样,从消息队列中读取消息,消息队列中对应的消息将被删除;
6. 每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的;
7. 只有内核重启或人工删除消息队列时,该消息队列才会被删除;若不人工删除消息队列,消息队列将一直存在于系统中

三 消息队列的创建和使用

System V提供的IPC通信机制需要一个key值,通过key值就可以在系统内获得一个唯一的消息队列标识符。key值可以人工指定,也可以通过ftok函数获得

3.1 获取系统唯一的key值

  1. 需要的头文件和函数原型
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
  1. 功能
获得项目相关的唯一的IPC键值
  1. 参数
pathname:路径名
proj_id:项目ID,非0整数(只有低8位有效)
  1. 返回值
成功:返回key值;
失败:返回-1

3.2 创建消息队列

  1. 需要的头文件和函数原型
#include <sys/msg.h>int msgget(key_t key, int msgflg);
  1. 功能
创建一个新的或者打开一个已经存在的消息队列。不同进程调用此函数,只有用相同的key值就能得到同一个消息队列的标识符
  1. 参数
key:IPC的key值
msgflg:标识函数的行为以及消息队列的权限msgflg的取值:IPC_CREAT:创建消息队列IPC_EXCL:检测消息队列是否存在位或权限位:消息队列位或权限位后可以设置消息队列的访问权限,格式和open函数的mode_t一样,但可执行权限未使用
  1. 返回值
成功:返回消息队列的标识符;
失败:返回-1


3.3 查看消息队列和删除消息队列的shell命令

  1. 查看消息队列
[root@ansible9 ~]# ipcs -q------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
0x01000080 0          root       666        0            0
  1. 删除消息队列

3.4 消息队列的信息格式的定义

消息队列的信息格式是需要人工定义的,格式放在一个结构体中;
信息结构体中的第一个long型的成员的作用是,只有对这类信息感兴趣的进程才能拿到这类信息

3.5 发送消息函数msgsnd

  1. 需要的头文件和函数原型
#include <sys/msg.h>int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  1. 功能
    向消息队列添加新消息
  2. 参数
msqid:消息队列标识符
msgp:要是的消息的结构体变量的地址
msgsz:消息正文的字节数(等于消息结构体的大小减去long类型的大小)
msgflg:函数的控制属性0:msgsnd调用阻塞直到条件满足为止IPC_NOWAIT:若消息没有立刻发送则调用该函数的进程会立刻返回
  1. 返回值
成功:0
失败:-1
  1. 实例

3.6 接收消息函数msgrcv

  1. 需要的头文件和函数原型
#include <sys/msg.h>ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
  1. 功能
    从标识符为msqid的信息队列中接收一个消息。一旦接收消息成功,则消息在消息队列中被删除
  2. 参数
msqid:消息队列的标识符,代表要从哪个消息队列中获取消息
msgp:存放消息的结构体地址
msgsz:消息正文的字节数
msgtyp:感兴趣的消息类型,可以有以下几种类型msgtyp=0:返回队列中第一个消息msgtyp>0:返回队列中消息类型为msgtyp的消息msgtyp<0:返回队列中消息类型小于等于msgtyp的绝对值的消息,如果这种消息有若干个,则取类型值最小的消息msgflg:函数的控制属性0:msgrcv调用阻塞直到接收消息成功为止MSG_NOERROR:若返回的消息字节数比nbytes字节数多,则消息就会截断到nbytes字节,且不通知消息发送进程;IPC_NOWAIT:调用进程会立即返回,若没有收到消息则立即返回-1
  1. 注意
若消息队列中有多种类型的消息,msgrcv获取消息的时候按消息类型获取,不是先进先出的;
在获取某类型消息的时候,若队列中有多条此类型的消息,则获取最先添加的消息,即先进先出;
  1. 返回值
成功:返回读取消息的长度;
失败:返回-1
  1. 实例
    发:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>int main(int arg, char *argv[])
{//获取IPC唯一key值keykey_t key = ftok("/",1);printf("%#x\n",key);//创建一个消息队列,队列标识符为msg_idint msg_id = msgget(key,IPC_CREAT|0666);printf("%d\n",msg_id);//定义消息队列的信息格式MSGtypedef struct msg{long type;char text[100];int a;char name[32];}MSG;//新建一个信息MSG msg;memset(&msg,0,sizeof(msg));msg.type=10;msg.a = 100;strcpy(msg.name,"andy");strcpy(msg.text,"ni hao");//发送上面新建的信息msgsnd(msg_id, &msg, sizeof(MSG)-sizeof(long),0);return 0;
}

收:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>int main(int arg, char *argv[])
{//获取IPC唯一key值keykey_t key = ftok("/",1);printf("%#x\n",key);//创建一个消息队列,队列标识符为msg_idint msg_id = msgget(key,IPC_CREAT|0666);printf("%d\n",msg_id);//定义消息队列的信息格式MSGtypedef struct msg{long type;char text[100];int a;char name[32];}MSG;//接收消息MSG msg;memset(&msg,0,sizeof(msg));msgrcv(msg_id, &msg, sizeof(MSG)-sizeof(long), 10,0);printf("发送者:%s\n", msg.name);printf("消息:%s\n", msg.text);return 0;
}

3.7 总结

不管是发送者还是接收者

1. ftok得到唯一key
2. msgget创建消息队列

发送者

3. MSG msg;
4. msg.mtype=接收感兴趣的类型值;
5. msgsnd(msg_id, &msg, sizeof(MSG)-sizeof(long), 0);//发送消息到消息队列

接收者

1. MSG msg;
2. msgrcv(msg_id, &msg, sizeof(MSG)-sizeof(long), 接收感兴趣的类型值, 0);

3.8 消息队列的控制

  1. 需要的头文件和函数原型
#include <sys/msg.h>int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  1. 功能
    对消息队列进行各种控制,如删除消息队列,修改消息队列的属性
  2. 参数
msqid:消息队列的标识符
cmd:函数功能的控制
buf:msqid_ds数据类型的地址,用来存放或更改消息队列的属性cmd函数功能的控制:IPC_RMID:删除由msqid标识的消息队列,将他从系统中删除并破坏相关的数据结构IPC_STAT:将msqid相关的数据结构中各个元素的当前值存入到由buf指向的结构中IPC_SET:将msqid相关的数据结构中的元素设置为由buf指向的结构中的对应值
  1. 返回值
成功:返回0;
失败:返回-1
  1. 实例
    a. 删除消息队列
int w = msgctl(msg_id,IPC_RMID,NULL);

b. 查看消息队列属性

四 消息队列练习题:实现多人聊天程序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>//定义人名和消息类型的对应关系
char *peple[3]  = {"andy:10","linda:20","tony:30"
};long type = 0; //消息类型//定义消息结构体
typedef struct _msg{long mtype; //接收者类型char content[100]; //发送的消息char name[20]; //发送者姓名
}MSG;//标记我是谁
char me[20]="";int main(int argc, char * kwargs[])
{//获取系统ipc keykey_t key = ftok("/",100);//创建消息队列int msg_id = msgget(key, IPC_CREAT|0666);printf("消息id:%d\n",msg_id);//创建两个子进程一个发消息,一个收消息int i = 0;for(;i<2;i++){pid_t pid = fork();if (pid == 0)break;}if(i==0) //第一个子进程负责发送消息{while(1){char who[32] = "";printf("给谁发送消息:");fgets(who,sizeof(who),stdin);who[strlen(who)-1]='\0';strcat(who,":");for(int n=0;n<3;n++){if(strncmp(who,peple[n],strlen(who))==0){char *tmp1;char name[10]="";memcpy(name,peple[n],strlen(peple[n]));tmp1 = strtok(name,":");tmp1 = strtok(NULL,":");type = atol(tmp1);break;}}  char msg[128] = "";printf("请输入要发送的消息:");fgets(msg,sizeof(msg),stdin);msg[strlen(msg)-1]='\0';//将消息放入消息队列MSG new_msg;new_msg.mtype = type;memcpy(new_msg.content,msg,strlen(msg));
#ifdef ANDYmemcpy(new_msg.name,"andy",sizeof("andy"));
#endif
#ifdef LINDAmemcpy(new_msg.name,"linda",sizeof("lnda"));
#endif
#ifdef TONYmemcpy(new_msg.name,"tony",sizeof("tony"));
#endif      int res = msgsnd(msg_id,&new_msg,sizeof(MSG)-sizeof(long),0);}}else if(i==1) //第二个子进程负责接收消息{while(1){MSG new_msg;char who[20];
#ifdef ANDYmemcpy(who,"andy:",strlen("andy:"));
#endif
#ifdef LINDAmemcpy(who,"linda:",strlen("linda:"));
#endif
#ifdef TONYmemcpy(who,"tony:",strlen("tony:"));
#endiffor(int n=0;n<3;n++){if(strncmp(who,peple[n],strlen(who)-1)==0){char *tmp1;char name[10]="";memcpy(name,peple[n],strlen(peple[n]));tmp1 = strtok(name,":");tmp1 = strtok(NULL,":");type = atol(tmp1);break;}}   //接收消息int res = msgrcv(msg_id,&new_msg,sizeof(MSG)-sizeof(long),type,0);printf("\r%s说:%s\n",new_msg.name,new_msg.content);printf("给谁发消息: ");fflush(NULL);} }else if(i==2) //父进程负责子进程资源回收{while(1){pid_t pid = waitpid(-1,NULL,WNOHANG);if(pid>0){printf("子进程%d退出了\n",pid);}else if(pid==0){continue;}else if(pid == -1){break;}}}return 0;
}

c语言系统编程八:Linux进程间通信之消息队列相关推荐

  1. Linux进程间通信——使用消息队列

    下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信--使用命名管道 一.什么是消息队列 消息队列提供了 ...

  2. linux 进程uhxuhao,linux 进程间通信三 消息队列以及实例

    转自 http://blog.csdn.net/liang890319/article/details/8280934 代码来自:嵌入式Linux应用开发标准教程 消息可以理解为写信给某个人,这里在应 ...

  3. Linux进程间通信(IPC)-------消息队列

    消息队列是进程间通信的一种方法,他有两个操作,一个进程来发送消息(也就是向内存中写入数据),另一个是获取消息(也就是另外一个进程在内存中读取数据) 下面来看消息队列的 创建,写入,读取等需要用到的函数 ...

  4. linux进程间通信:消息队列实现双端通信

    双端通信描述 利用消息队列针对发送接受消息的类型唯一性 进行多个客户端之间消息传递,而不需要server端进行消息转发. 同时消息队列的读阻塞和写阻塞特性(消息队列中已经写入数据,如果再不读出来,则无 ...

  5. linux 消息对lie_Linux进程间通信之消息队列总结

    一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符( i d ...

  6. linux消息通信无法接收,进程间通信:消息队列有关问题:进程1接收不到进程2的消息...

    进程间通信:消息队列有关问题:进程1接收不到进程2的消息 进程间通信:消息队列有关问题:进程1接收不到进程2的消息 日期:2014-05-16 浏览次数:20365 次 进程间通信:消息队列问题:进程 ...

  7. 进程间通信之消息队列

    一.什么是消息队列 unix早期通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便.消息队列(也叫做报文队列)则克服了这些缺点. 消息队列就是一个消息 ...

  8. java异步处理_Java编程开发好入门吗 消息队列的用途有哪些

    Java编程开发好入门吗?消息队列的用途有哪些?消息队列是指能够提供消息排队消费功能的软件程序,是消息队列中间件的一部分.消息队列中间件是分布式系统中重要的组件.接下来就给大家讲解消息队列的优势.类型 ...

  9. c语言系统编程六:Linux进程间通信之无名管道

    Linux进程间通信之无名管道 一 文件描述符复制 1.1 dup函数(复制文件描述符) 1.2 dup2函数(复制文件描述符) 二 无名管道的概述 三 无名管道的特点 四 无名管道的创建和使用 4. ...

最新文章

  1. oracle 06502 解决,ora-06502如何解决。。。
  2. wireshrk中的名词说明
  3. 如何使用用户数据脚本在EC2实例上安装Apache Web Server
  4. Java native方法availableProcessors()获取处理器数量的底层C++实现
  5. android常见传值
  6. bch怎么挖_BCH与BSV的减半,给目前正在反弹中的行情带来什么?
  7. DaveGray推荐的视觉思维好书(一)
  8. Imdisk 虚拟磁盘 » A programmer's site
  9. win10磁盘管理教程
  10. 14.Veeam BR14 配置信息备份与恢复
  11. cps评分和tps评分_一文总结:PD-1/PD-L1免疫检查点抑制剂和TPS、CPS、IPS
  12. dell服务器uefi启动u盘安装系统,uefi启动u盘安装系统怎么装|uefi u盘启动装系统步骤...
  13. eclipse运行java总显示上一个程序的运行结果(解决方案)
  14. windows不能同时连接有线和无线
  15. linux - 安装Ubuntu20.04.5版本
  16. 宝塔win安装提示非服务器系统,宝塔windows面板安装
  17. oracle rfs进程过多,oracle 11.2 DataGuard少了日志应用进程RFS
  18. 电阻组合c语言程序,【C语言及程序设计】项目1-4-2-2:计算并联电阻
  19. 微软的Edge浏览器越来越有趣
  20. IntelliJ IDEA创建Servlet最新方法 Idea版本2021以及IntelliJ IDEA创建Servlet 404问题,找不到对应的路径。

热门文章

  1. 联通爱苹果,移动抢苹果
  2. 我的Python程序太慢了。如何加快速度?
  3. 安卓保活(华为,OPPO,vivo,小米)
  4. 多线程导入Excel
  5. 成功转行,从一个机械攻城狮变为程序猿的坎坷之路
  6. THREE + d3制作中国地图挤压(extrude)模型
  7. 社区便利店选址五要素,真实案例分析便利店选址步骤分享!
  8. 虚拟机中wget命令的安装
  9. 问题 H: 嚎叫响彻在贪婪的厂房
  10. Python关键字及含义