• 【IPC】消息队列


    1、IPC对象

    除了最原始的进程间通信方式信号、无名管道和有名管道外,还有三种进程间通信方式,这
    三种方式称之为IPC对象
    IPC对象分类:消息队列、共享内存、信号量(信号灯集)
    IPC对象也是在内核空间开辟区域,每一种IPC对象创建好之后都会将其设置为全局,并且
    会给其分配一个编号,只要找到唯一的这个编号就可以进行通信,所以不相关的进程可以通
    过IPC对象通信。
    IPC对象创建好之后,会在当前系统中可见,只要不删除或者不关闭系统,就会一直存在。
    查看已经创建的IPC对象:
      ipcs 查看当前系统中所有创建的 IPC 对象
      ipcs ‐q 查看创建的消息队列
      ipcs ‐m 查看创建的共享内存
      ipcs ‐s 查看信号量
      ipcrm 删除 IPC 对象
      例如: ipcrm ‐q msqid 删除标号为 msqid 的消息队列

    2、消息队列的概述

    2.1 消息队列的概念

    消息队列是消息的链表,存放在内存中,由内核维护
    消息队列的特点
    1、消息队列中的消息是有类型的。
    2、消息队列中的消息是有格式的。
    3、消息队列可以实现消息的随机查询。消息不一定要以先进先出的次序读取,编程时可以
    按消息的类型读取
    4、消息队列允许一个或多个进程向它写入或者读取消息。
    5、与无名管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删
    6、每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的。
    7、只有内核重启或人工删除消息队列时,该消息队列才会被删除。若不人工删除消息队
    列,消息队列会一直存在于系统中。
    在ubuntu 12.04中消息队列限制值如下:
    每个消息内容最多为8K字节
    每个消息队列容量最多为16K字节
    系统中消息队列个数最多为1609个
    系统中消息个数最多为16384个
    System V提供的IPC通信机制 需要一个key值通过key值就可在系统内获得一个唯一的消
    息队列标识符
    key值可以是人为指定的,也可以通过ftok函数获得
    如果多个进程想通过IPC对象通信,则必须找到唯一的标识,而唯一的标识是由key决定
    的,所以只要key知道,则就可以实现多个进程通信
    (另外,Posix IPC的操作稍有不同,后面补充)

    2.2 ftok函数

    ftok - convert a pathname and a project identifier to a System V IPC key
     
      #include
      #include
      key_t ftok ( const char *pathname, int proj_id );
      功能:通过文件名和目标值共同创造一个键值并返回值
      参数:
               pathname :任意一个文件名(文件名或者目录名)
             proj_id:目标值,范围一般是 0~127
      返回值:
                      成功:键值
                      失败: ‐1
      如果使用 ftok 函数获取键值,得到的键值是由 ftok 的第一个   参数对应文件的信息和第二个参数一起决定的
    1. #include
    2. #include
    3. #include
    4. #include
    5. int main(int argc, char const *argv[])
    6. {
    7. //使用ftok函数获取键值
    8. //只要保证ftok的第一个参数对应的文件和第二个参数值相同,则不管程序运行多少遍或者多少个进程或者键值
    9. //键值一定都是唯一的
    10. key_t mykey;
    11. mykey = ftok("test",666);
    12. if(mykey==-1){
    13. perror("fail to ftok");
    14. exit(1);
    15. }
    16. printf("mykey = %#x\n", mykey);
    17. return 0;
    18. }

    3、消息队列操作

    3.1创建消息队列 -- msgget()

      #include
      #include
      #include
      int msgget ( key_t key, int msgflg );
              功能:创建一个消息队列,得到消息队列的 id
    参数:
              key :键值,唯一的键值确定唯一的消息队列
                      方法 1 :任意指定一个数
                      方法 2 :使用 ftok 函数获取键值
              msgflg :消息队列的访问权限,
              一般设置为 IPC_CREAT | IPC_EXCL | 0777 或者 IPC_CREAT | 0777
      返回值:
              成功:消息队列的 id
            失败:‐1
    查看消息队列
      ipcs ‐q
      删除消息队列
      ipcrm ‐q msqid
    测试msgget
    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main(int argc, char const *argv[])
    8. {
    9. key_t mykey;
    10. mykey = ftok("test", 666);
    11. if (mykey == -1)
    12. {
    13. perror("fail to ftok");
    14. exit(1);
    15. }
    16. printf("mykey = %#x\n", mykey);
    17. // 通过msgget函数创建一个消息队列
    18. int msgid;
    19. msgid = msgget(mykey, IPC_CREAT | 0666);
    20. if (msgid == -1)
    21. {
    22. perror("fail to msgget");
    23. exit(1);
    24. }
    25. printf("msgid = %d\n", msgid);
    26. system("ipcs -q");
    27. return 0;
    28. }

    3.2 发送消息-- msgsnd()

      # include
      # include
    # include
      int msgsnd ( int msqid , const void * msgp , size_t msgsz , int msgflg );
      功能:向指定的消息队列发送数据(写操作)
      参数:
      msqid
            消息队列的id
    msgp
            要写入的数据,需要自己定义结构体
    struct struct_name {
              long mtype ; // 消息的编号,必须大于 0
              char mtext [ 128 ]; // 消息正文,可以定义多个成员
              ...
      }
      msgsz :消息正文的大小,不包括消息的编号长度
      msgflg :标志位
              0 阻塞
              IPC_NOWAIT 非阻塞
      返回值:
              成功: 0
              失败: 1
    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define N 128
    8. typedef struct
    9. {
    10. long msg_type; //消息类型,必须在结构体的第一个位置并且类型必须是long
    11. char msg_text[N]; //消息正文,也可以有多个成员并且类型也可以是任意
    12. }MSG ;
    13. #define MSG_SIZE (sizeof(MSG)-sizeof(long))
    14. int main(int argc, char const *argv[])
    15. {
    16. key_t mykey;
    17. mykey = ftok("test", 666);
    18. if (mykey == -1)
    19. {
    20. perror("fail to ftok");
    21. exit(1);
    22. }
    23. printf("mykey = %#x\n", mykey);
    24. // 通过msgget函数创建一个消息队列
    25. int msgid;
    26. msgid = msgget(mykey, IPC_CREAT | 0666);
    27. if (msgid == -1)
    28. {
    29. perror("fail to msgget");
    30. exit(1);
    31. }
    32. //printf("msgid = %d\n", msgid);
    33. system("ipcs -q");
    34. MSG msg1 ={1,"hello world"};
    35. MSG msg2 ={3,"UCC"};
    36. MSG msg3 ={2,"giant"};
    37. MSG msg4 ={4,"美利达"};
    38. if(msgsnd(msgid,&msg1,MSG_SIZE,0)==-1){
    39. perror("fail to send");
    40. exit(1);
    41. }
    42. if(msgsnd(msgid,&msg2,MSG_SIZE,0)==-1){
    43. perror("fail to send");
    44. exit(1);
    45. }
    46. if(msgsnd(msgid,&msg3,MSG_SIZE,0)==-1){
    47. perror("fail to send");
    48. exit(1);
    49. }
    50. if(msgsnd(msgid,&msg4,MSG_SIZE,0)==-1){
    51. perror("fail to send");
    52. exit(1);
    53. }
    54. system("ipcs -q");
    55. return 0;
    56. }

    3.3 消息接收--msgrcv()

    # include
    # include
      ssize_t msgrcv ( int msqid , void * msgp , size_t msgsz ,
      long msgtyp , int msgflg );
      功能:从消息队列中接收数据(读操作),接收的数据会从消息队列中删除
      参数:
      msqid
            消息队列id
      msgp
            保存接收到的数据的结构体
            struct struct_name {
                    long mtype ; // 消息的编号,必须大于 0
                    char mtext [ 128 ]; // 消息正文,可以定义多个成员
            }
      msgsz
            消息正文的大小
      msgtyp :设置要接收哪个消息
              0 按照写入消息队列的顺序依次读取
              > 0 只读取消息队列中消息编号为当前参数的第一个消息
              < 0 只读取消息队列中小于等于当前参数的绝对中内最小的第一个消息
     
    msgflg :标志位
            0 阻塞
              IPC_NOWAIT 非阻塞
      返回值:
              成功:接收到的消息正文的长度
              失败: 1
    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define N 128
    8. typedef struct
    9. {
    10. long msg_type; //消息类型,必须在结构体的第一个位置并且类型必须是long
    11. char msg_text[N]; //消息正文,也可以有多个成员并且类型也可以是任意
    12. }MSG ;
    13. #define MSG_SIZE (sizeof(MSG)-sizeof(long))
    14. int main(int argc, char const *argv[])
    15. {
    16. key_t mykey;
    17. mykey = ftok("test", 666);
    18. if (mykey == -1)
    19. {
    20. perror("fail to ftok");
    21. exit(1);
    22. }
    23. printf("mykey = %#x\n", mykey);
    24. // 通过msgget函数创建一个消息队列
    25. int msgid;
    26. msgid = msgget(mykey, IPC_CREAT | 0666);
    27. if (msgid == -1)
    28. {
    29. perror("fail to msgget");
    30. exit(1);
    31. }
    32. //printf("msgid = %d\n", msgid);
    33. system("ipcs -q");
    34. //通过msgrcv函数接收消息队列中的信息(读操作)
    35. //注意:如果没有第四个参数指定的消息时,msgrcv函数会阻塞等待
    36. MSG msg;
    37. //如果第四个参数为0,则按照先进先出的方式读取数据
    38. //if(msgrcv(msgid,&msg,MSG_SIZE,0,0))
    39. //如果第四个参数为>0,则获取当前值得消息类型的数据
    40. //if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 2, 0) == ‐1)
    41. //如果第四个参数为<0,则获取当前值得绝对值内消息类型最小的数据
    42. if(msgrcv(msgid, &msg, MSG_SIZE, -3, 0) == -1)
    43. {
    44. perror("fail to msgrcv");
    45. exit(1);
    46. }
    47. printf("recv_msg = %s\n", msg.msg_text);
    48. system("ipcs -q");
    49. return 0;
    50. }

  • 相关阅读:
    Cy3/5/7标记多肽/PEG/聚合物/磷脂----为华生物
    【广州华锐互动】VR虚拟现实旅游:改变游客旅游方式,提升旅游体验
    Spring Boot 异步线程静态获取request对象为空 RequestContextHolder 为空 Java 异步线程获取request为空
    前端菜鸡学习日记 -- computed和watch的用法
    DOM—DOM 事件基础知识点总结
    idea 实用 高效 插件 分享 记录
    如何在Asp.Net Core中注册同一接口的多个实现?
    正点原子嵌入式linux驱动开发——U-boot移植
    Programming Differential Privacy第九章
    进阶JS-作用域和作用域链
  • 原文地址:https://blog.csdn.net/Alex_cf/article/details/134487387