• lv5 嵌入式开发-11 消息队列


    掌握:消息队列机制、打开/创建消息队列、发送消息、接收消息

    1 消息队列

    消息队列是System V IPC对象的一种

    消息队列由消息队列ID来唯一标识

    消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等

    消息队列可以按照类型来发送/接收消息

    消息队列结构

    内核中已实现的数据结构:链表

    进程A放入数据,进程B可访问并取出。

    2 消息队列使用步骤 

    发送端:

            1 申请key

            2 打开/创建消息队列   msgget

            3 向消息队列发送消息   msgsnd

    接收端:

            1 打开/创建消息队列   msgget

            2 从消息队列接收消息   msgrcv

            3 控制(删除)消息队列   msgctl

    2.1 消息队列创建/打开 – msgget

    1. #include
    2. #include
    3. int msgget(key_t key, int msgflg);
    • 成功时返回消息队列的id,失败时返回EOF  
    • key 和消息队列关联的key  IPC_PRIVATE 或 ftok  
    • msgflg  标志位  IPC_CREAT|0666  没有创建,有则打开。

    示例

    1. int main() {
    2. int msgid;
    3. key_t key;
    4. if ((key = ftok(“.”, ‘q’)) == -1) {
    5. perror(“ftok”); exit(-1);
    6. }
    7. if ((msgid = msgget(key, IPC_CREAT|0666)) < 0) {
    8. perror(“msgget”); exit(-1);
    9. }
    10. ……
    11. return 0;
    12. }

    2.2 消息发送 – msgsnd

    1. #include
    2. #include
    3. int msgsnd(int msgid, const void *msgp, size_t size,
    4. int msgflg);
    • 成功时返回0,失败时返回-1  
    • msgid   消息队列id  
    • msgp    消息缓冲区地址  
    • size    消息正文长度  
    • msgflg   标志位 0 或 IPC_NOWAIT

            0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列

            IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回

    2.3 消息格式

    • 通信双方首先定义好统一的消息格式
    • 用户根据应用需求定义结构体类型
    • 首成员类型必须为long,代表消息类型(正整数)
    • 其他成员都属于消息正文
    • 消息长度不包括首类型 long

    示例:

    1. typedef struct {
    2. long mtype;
    3. char mtext[64];
    4. } MSG;
    5. #define LEN (sizeof(MSG) – sizeof(long))
    6. int main() {
    7. MSG buf;
    8. ……
    9. buf.mtype = 100;
    10. fgets(buf.mtext, 64, stdin);
    11. msgsnd(msgid, &buf,LEN, 0);
    12. ……
    13. return 0;
    14. }

    注意:

    1 消息结构必须有long类型的msg_type字段,表示消息的类型。

    2消息长度不包括首类型 long

     

    2.4 消息接收 – msgrcv

    1. #include
    2. #include
    3. int msgrcv(int msgid, void *msgp, size_t size, long msgtype,
    4. int msgflg);
    • 成功时返回收到的消息长度,失败时返回-1  
    • msgid   消息队列id  
    • msgp   消息缓冲区地址  
    • size   指定接收的消息长度  
    • msgtype   指定接收的消息类型    
    • msgflg   标志位   0 或 IPC_NOWAIT        

            msgtype=0:收到的第一条消息,任意类型。

            msgtype>0:收到的第一条 msg_type类型的消息。

            msgtype<0:接收类型等于或者小于msgtype绝对值的第一个消息

    例子:如果msgtype=-4,只接受类型是1、2、3、4的消息

    示例 

    1. typedef struct {
    2. long mtype;
    3. char mtext[64];
    4. }MSG;
    5. #define LEN (sizeof(MSG) – sizeof(long))
    6. int main() {
    7. MSG buf;
    8. ……
    9. if (msgrcv(msgid, &buf,LEN, 200, 0) < 0) {
    10. perror(“msgrcv”);
    11. exit(-1);
    12. }
    13. ……
    14. }

    2.5 控制消息队列 – msgctl

    1. #include
    2. #include
    3. int msgctl(int msgid, int cmd, struct msqid_ds *buf);
    • 成功时返回0,失败时返回-1  
    • msgid    消息队列id  
    • cmd    要执行的操作  IPC_STAT / IPC_SET / IPC_RMID  (删除)
    • buf   存放消息队列属性的地址

    2.6 示例(编写实现两个进程实现消息队列通信的程序)

     示例:发送消息队列

    1. #include
    2. #include
    3. #include
    4. #include
    5. typedef struct{
    6. long msg_type;
    7. char buf[128];
    8. }msgT;
    9. #define MSGLEN (sizeof(msgT)-sizeof(long))
    10. int main(){
    11. key_t key;
    12. int msgid;
    13. int ret;
    14. msgT msg;
    15. key = ftok(".",100); //创建key
    16. if(key<0){
    17. perror("ftok");
    18. return 0;
    19. }
    20. msgid = msgget(key,IPC_CREAT|0666); //创建消息队列
    21. if(msgid<0){
    22. perror("msgget");
    23. return 0;
    24. }
    25. msg.msg_type = 1;
    26. strcpy(msg.buf,"this msg type 1");
    27. ret = msgsnd(msgid,&msg,MSGLEN,0);
    28. if(ret<0){
    29. perror("msgsnd");
    30. return 0;
    31. }
    32. msg.msg_type = 2;
    33. strcpy(msg.buf,"this msg type 2");
    34. ret = msgsnd(msgid,&msg,MSGLEN,0);
    35. if(ret<0){
    36. perror("msgsnd");
    37. return 0;
    38. }
    39. msg.msg_type = 3;
    40. strcpy(msg.buf,"this msg type 3");
    41. ret = msgsnd(msgid,&msg,MSGLEN,0);
    42. if(ret<0){
    43. perror("msgsnd");
    44. return 0;
    45. }
    46. msg.msg_type = 4;
    47. strcpy(msg.buf,"this msg type 4");
    48. ret = msgsnd(msgid,&msg,MSGLEN,0);
    49. if(ret<0){
    50. perror("msgsnd");
    51. return 0;
    52. }
    53. msg.msg_type = 5;
    54. strcpy(msg.buf,"this msg type 5");
    55. ret = msgsnd(msgid,&msg,MSGLEN,0);
    56. if(ret<0){
    57. perror("msgsnd");
    58. return 0;
    59. }
    60. }

    查看消息队列 

    示例:消息接收和删除

    1. #include
    2. #include
    3. #include
    4. #include
    5. typedef struct{
    6. long msg_type;
    7. char buf[128];
    8. }msgT;
    9. #define MSGLEN (sizeof(msgT)-sizeof(long))
    10. int main(){
    11. int msgid;
    12. key_t key;
    13. msgT msg;
    14. int ret;
    15. key = ftok(".",100);
    16. if(key<0){
    17. perror("ftok");
    18. return 0;
    19. }
    20. msgid = msgget(key,IPC_CREAT|0666);
    21. if(msgid<0){
    22. perror("msgget");
    23. return 0;
    24. }
    25. int count=0;
    26. while(1){ //连续接收
    27. //ret = msgrcv(msgid,&msg,MSGLEN,3,0); //只接收类型3
    28. //ret = msgrcv(msgid,&msg,MSGLEN,-3,0); //只接收类型1、2、3
    29. ret = msgrcv(msgid,&msg,MSGLEN,0,0); //全部接收
    30. if(ret<0){
    31. perror("msgrcv");
    32. return 0;
    33. }
    34. count++;
    35. if(count>3){
    36. break;
    37. }
    38. printf("receiv msg type=%d,buf=%s\n",(int)msg.msg_type,msg.buf);
    39. }
    40. ret = msgctl(msgid,IPC_RMID,NULL);
    41. if(ret<0){
    42. perror("msgctl");
    43. return 0;
    44. }
    45. }

  • 相关阅读:
    远程导入MySQL数据量大速度慢问题
    计算机毕业设计Java校园社团管理系统(源码+系统+mysql数据库+Lw文档)
    Alien Skin Exposure2024胶片滤镜中文免费版插件
    因果系列文章(7)——干预工具(下)
    基于MATLAB的随机搜索算法优化带有速度的路由网络
    基于C#+SQLServer开发的餐饮管理系统源码
    在Tomcat中启用虚拟线程特性
    openGauss数据库的安装部署
    (214)Verilog HDL:状态机实现使能移位寄存器
    配置nginx动静分离全步骤
  • 原文地址:https://blog.csdn.net/m0_60718520/article/details/133437551