设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 数据 手机
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

Linux下消息队列学习笔记

发布时间:2022-06-16 14:10 所属栏目:48 来源:互联网
导读:消息队列是进程间通讯的一种方法,一开始我以为消息队列是类似一个管道,一头连接一个进程、一头连接另一个进程,只能由这两个进程来进行互相的读写,其实这是错的,消息队列是系统层面的,它不属于某两个进程,它是由系统维护的一个链表结构,对消息队列的读写就是
  消息队列是进程间通讯的一种方法,一开始我以为消息队列是类似一个管道,一头连接一个进程、一头连接另一个进程,只能由这两个进程来进行互相的读写,其实这是错的,消息队列是系统层面的,它不属于某两个进程,它是由系统维护的一个链表结构,对消息队列的读写就是一个对链表的操作,默认是在链表的一端写数据,另一端读数据(先进先出),进程也可以取指定某种消息类型的消息.
 
  在一个进程里创建了消息队列,且是可读可写的,那么系统中的所有进程都可以对它进行读写操作.
 
  1、打开或创建一个消息队列
 
  原型:int msgget(key_t key, int msgflg);
 
  参数:
 
  1)key:消息队列的key值。
 
  2)msgflg:
 
  IPC_CREAT:如果key对应的消息队列对象不存在,则创建,否则则进行打开操作,返回0.
 
  IPC_EXCL:如果key对应的消息队列对象不存在,则返回-1;否则则进行打开操作,返回0。
 
  权限控制:0666表示可读可写,和上面的IPC_CREAT做逻辑或操作.
 
  返回值:成功返回,创建的或打开的消息队列的id,失败返回-1.
 
  例子程序:test1.c,代码如下:
 
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/msg.h>
  #include <stdio.h>
  int main(void)
  {
   int msgid;
   printf("this is test1!\n");
  
   msgid = msgget(1001, 0666|IPC_CREAT);
   printf("msgid = %d\n", msgid);
  
   return 0;
  }
  执行结果:
 
  [root@server ~]# gcc -o test1 test1.c
  [root@server ~]# ./test1
  this is test1!
  msgid = 32768
  [root@server ~]# ipcs
  ------ Shared Memory Segments --------
  key        shmid      owner      perms      bytes      nattch     status      
  ------ Semaphore Arrays --------
  key        semid      owner      perms      nsems      
  0x00000000 0          root       600        1         
  ------ Message Queues --------  //phpfensi.com
  key        msqid      owner      perms      used-bytes   messages     
  0x000003e9 32768      root       666        0            0      
  从ipcs命令的结果可以知道,消息队列在创建它的进程退出后,还存在于系统中,说明消息队列是系统一层的,并不是属于某个进程的.
 
  2、设置消息队列属性(包括删除)
 
  原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
 
  参数:
 
  1)msqid:消息队列的id.
 
  2)cmd:执行的控制命令.
 
  IPC_STAT:读取消息队列属性,取得此队列的msqid_ds 结构,并将其存放在buf指向的结构中.
 
  IPC_SET:设置消息队列属性.
 
  IPC_RMID:删除消息队列.
 
  IPC_INFO:读取消息队列基本情况,此命令等同于 ipcs 命令.
 
  例子程序:test2.c,代码如下:
 
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/msg.h>
  #include <stdio.h>
  int main(void)
  {
   int i;
   printf("this is test2!\n");
   i = msgctl(32768, IPC_RMID, NULL);//这里已经知道消息id等于32768
   if (0 == i)
   {
    printf("msq deleted!\n");
   }
   return 0;
  }
  //执行结果:
  [root@server ~]# gcc -o test2 test2.c
  [root@server ~]# ./test2
  this is test2!
  msq deleted!
  [root@server ~]# ipcs
  ------ Shared Memory Segments --------
  key        shmid      owner      perms      bytes      nattch     status      
  ------ Semaphore Arrays --------
  key        semid      owner      perms      nsems      
  0x00000000 0          root       600        1         
  ------ Message Queues --------
  key        msqid      owner      perms      used-bytes   messages
  原有的消息队列被删除了.
 
  3、向消息队列写/读消息
 
  原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
 
  原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
 
  参数:
 
  1)msqid:消息队列的id.
 
  2)msgp:指向消息缓冲区的指针,该指针指向如下的一个用户可定义的通用结构.
 
  struct mymsg {
    long mtype;
    char mbuf[1024];
  };
  3)msgsz:消息的大小。
 
  4)msgflg:可以为IPC_NOWAIT或0,表示操作是阻塞式的还是非阻塞式的,设置为IPC_NOWAIT,在msgsnd()中,如果消息队列已经满了,则不会阻塞,立即返回-1(EAGAIN).
 
  在msgrcv()中,如果消息队列为空,则不做等待,立即返回-1(ENOMSG),设置为0,在msgsnd()中,进程阻塞直到(a)有空间可以容纳要发送的消息;或(b)从系统中删除了此队列(返回EIDRM);或(c)捕捉到一个信号,并从信号处理程序返回(返回EINTR)。
 
  在msgrcv()中,进程阻塞直到(a)有了指定类型的消息;或(b)从系统中删除了此队列(返回EIDRM);或(c)捕捉到一个信号并从信号处理程序返回(返回EINTR)。
 
  5)msgtype:用于msgrcv()函数,指定消息的类型。相当于区分消息类别的标志位。
 
  msgtype = 0,返回消息队列中的第一个消息。
 
  返回值:
 
  msgsnd(),成功返回0,出错返回-1。
 
  msgrcv(),成功返回消息数据部分的长度,出错返回-1。
 
  例子程序:test3.c,代码如下:
 
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/msg.h>
  #include <stdio.h>
  #include <errno.h>
  typedef struct
  {
   long mtype;
   char mbuf[1024];
  }mymsg;
  int main(void)
  {
   int i;
   int msgid1, msgid2;
   mymsg message1, message2, message3;
  
   printf("this is test3!\n");
  
   msgid1 = msgget(1002, 0666|IPC_CREAT);//key 1002
   if (msgid1 < 0)
   {
    printf("create key=1002 error, errno=%d\n", errno);
    exit(-1);
   }
   msgid2 = msgget(1003, 0666|IPC_CREAT);//key 1003
   if (msgid2 < 0)
   {
    printf("create key=1003 error, errno=%d\n", errno);
    exit(-1);
   }
   //初始化
   message1.mtype = 1;//设定一个消息类型
   memcpy(message1.mbuf, "first message", 13);
   message3.mtype = 1;
   memcpy(message3.mbuf, "hello test4.", 12);
  
   //test3进程在msgid1上发消息
   i = msgsnd(msgid1, (void *)&message1, strlen(message1.mbuf)+1, 0);
   if (i < 0)
   {
    printf("send message1 error, errno=%d\n", errno);
    exit(-1);
   }
  
   //test3进程从msgid1取消息,存到message2中
   i = msgrcv(msgid1, (void *)&message2, 1024, 0, 0);
   if (i < 0)
   {
    printf("rev error, errno=%d\n", errno);
    exit(-1);
   }
   else
   {
    //显示取出的消息
    printf("%s\n", message2.mbuf);
   }
   //test3进程在msgid2上发消息
   i = msgsnd(msgid2, (void *)&message3, strlen(message3.mbuf)+1, 0);
   if (i < 0)
   {
    printf("send message3 error, errno=%d\n", errno);
    exit(-1);
   }
  
   return 0;
  }
  例子程序:test4.c,代码如下:
 
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/msg.h>
  #include <stdio.h>
  #include <errno.h>
  typedef struct
  {
   long mtype;
   char mbuf[1024];
  }mymsg;
  int main(void)
  {
   int i, j;
   mymsg message;
  
   printf("this is test4!\n");
  
   i = msgget(1003, 0666|IPC_CREAT);
   if (i < 0)
   {
    printf("create key=1003 error, errno=%d\n", errno);
    exit(-1);
   }
  
   //test4进程在key=1003的消息队列上取消息
   j = msgrcv(i, (void *)&message, 1024, 0, 0);
   if (j < 0)
   {
    printf("rev error, errno=%d\n", errno);
    exit(-1);
   }
   else
   {
    //显示取出的消息
    printf("%s\n", message.mbuf);
   }
  
   return 0;
  }
  开两个终端,一个执行test3,另一个执行test4.
 
  test3执行结果,代码如下:
 
  [root@server ~]# ./test3
  this is test3!
  first message
  ipcs命令能看到key=1003的消息队列中有一条消息,使用了13字节长度,代码如下:
 
  key        msqid      owner      perms      used-bytes   messages
  0x000003ea 98305      root       666        0            0        
  0x000003eb 131074     root       666        13           1        
  //test4执行结果:
  [root@server ~]# ./test4
  this is test4!
  hello test4.
  以上.

(编辑:ASP站长网)

    网友评论
    推荐文章
      热点阅读