linux 消息队列

消息队列是在两个进程间传递二进制数据的方法。每个数据块都有一个类型,接受方可以根据类型来有选择地接受数据,不需要像管道一样必须按照先进先出的顺序。

linux消息队列有四个系统调用:msgget, msgsnd, msgrcv, msgctl

msgget

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgget(key_t key, int msgflg);

 

创建/获取一个消息队列。key是唯一键值,标识一个全局唯一的消息队列。msgflg指定权限

成功时返回一个正整数,是消息队列的标识符。失败返回-1,并设置errno

msgsnd

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

 

把一条消息添加到消息队列中。

msqid 是 msgget 返回的标识符。

msgp 指针指向一个准备发送的数据,必须使用这个结构体:

/* Template for struct to be used as argument for `msgsnd' and `msgrcv'.  */
struct msgbuf
  {
    __syscall_slong_t mtype;    /* type of received/sent message */
    char mtext[1];      /* text of the message */
  };

 

mtype指定消息类型,必须是一个正整数。mtext是消息数据。

参数msgsz是mtext的长度,这个值可以是0,表示没有数据

参数msgflg 是控制msgsnd的行为。通常设置为 IPC_NOWAIT ,即是以非阻塞的方式发送消息。默认情况下,如果发送消息时,消息队列满了,则 msgsnd 将阻塞。如果 IPC_NOWAIT 被设置,则 msgsnd 将立刻返回并设置 erno 为 EAGAIN.

成功时返回0,失败返回-1,并设置errno

msgrcv

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

从消息队列中获取消息。

msgp 是 struct msgbuf类型的指针,msgsz 指定消息数据部分的长度

msgtyp 指定接受哪种类型的消息:

msgtyp 定于0, 读取消息队列中第一个消息

msgtyp 大于0, 读取消息队列中第一个类型为msgtyp的消息

msgtyp 小于0, 读取消息队列中第一个类型值比msgtyp的绝对值小的消息。

参数msgflg 控制msgrcv的行为。可取下列值按位或运算:

IPC_NOWAIT。如果消息队列没有消息,则 msgrcv 调用立即返回并设置errno 为 ENOMSG

MSG_EXCEPT. 如果msgtyp大于0, 接受消息队列中第一个不是msgtyp类型的消息

MSG_NOERROR。如果消息数据部分长度超过了 msgsz,将它截断。

函数成功时,返回接受的mtext长度。失败返回-1,并设置errno

msgctl

int msgctl(int msqid, int cmd, struct msqid_ds *buf)

  设置消息队列的属性。

struct msqid_ds 结构体定义为:

/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct msqid_ds {
    struct ipc_perm msg_perm;
    struct msg *msg_first;      /* first message on queue,unused  */
    struct msg *msg_last;       /* last message in queue,unused */
    __kernel_time_t msg_stime;  /* last msgsnd time */
    __kernel_time_t msg_rtime;  /* last msgrcv time */
    __kernel_time_t msg_ctime;  /* last change time */
    unsigned long  msg_lcbytes; /* Reuse junk fields for 32 bit */
    unsigned long  msg_lqbytes; /* ditto */
    unsigned short msg_cbytes;  /* current number of bytes on queue */
    unsigned short msg_qnum;    /* number of messages in queue */
    unsigned short msg_qbytes;  /* max number of bytes on queue */
    __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
    __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};

 

msqid 是消息队列标识符。cmd 指定要执行的命令,其中

IPC_STAT.将消息队列关联的内核数据结构复制到 buf 中

IPC_RMID.立即删除消息队列标识符。唤醒所有等待读消息和写消息的进程(这些调用立即返回,并设置errno为 EIDRM)

还有其他命令,这里没有全部列举

函数失败返回-1

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>


struct msgbuf_
{
    long mtype;
    char mtext[64];
};

int main()
{
    int msgid = msgget(0, 0666);

    pid_t pid = fork();
    if (pid > 0)
    {
        struct msgbuf_ bufsnd = {8, "send data type 8"};
        if (-1 == msgsnd(msgid, &bufsnd, strlen(bufsnd.mtext), 0))
        {
            fprintf(stderr, "msgsnd: %d, %s\n", errno, strerror(errno));
            exit(1);
        }

        bufsnd.mtype = 9;
        strcpy(bufsnd.mtext, "this type is 9");
        if (-1 == msgsnd(msgid, &bufsnd, strlen(bufsnd.mtext), 0))
        {
            fprintf(stderr, "msgsnd: %d, %s\n", errno, strerror(errno));
            exit(1);
        }

        waitpid(pid, NULL, 0);
        if (-1 == msgctl(msgid, IPC_RMID, NULL))
        {
            fprintf(stderr, "msgctl: %d, %s\n", errno, strerror(errno));
            exit(1);
        }
    }
    else if (0 == pid)
    {
        struct msgbuf_ bufrcv;

        int lenrcv = msgrcv(msgid, &bufrcv, 64, 9, 0);
        if (lenrcv < 0)
        {
            fprintf(stderr, "msgrcv: %d, %s\n", errno, strerror(errno));
            exit(1);
        }
        printf("recv len=%d, type=%ld: %s\n", lenrcv, bufrcv.mtype, bufrcv.mtext);

        memset(&bufrcv, 0, sizeof(bufrcv));
        lenrcv = msgrcv(msgid, &bufrcv, 64, 8, 0);
        if (lenrcv < 0)
        {
            fprintf(stderr, "msgrcv: %d, %s\n", errno, strerror(errno));
            exit(1);
        }
        printf("recv len=%d, type=%ld: %s\n", lenrcv, bufrcv.mtype, bufrcv.mtext);
    }

    return 0;
}

 

posted @ 2018-09-15 16:42  二狗啸地  阅读(1002)  评论(0编辑  收藏  举报