zoukankan      html  css  js  c++  java
  • 【linux高级程序设计】(第十一章)System V进程间通信 2

    消息队列

    消息队列是消息的链式队列,模型如下:

    包括两种数据结构:

    msqid_ds消息队列数据结构

    msg消息队列数据结构

    struct msg_msg{
        struct list_head m_list;
        long m_type;  //消息类型
        int m_ts;     //消息大小
        struct msg_msgseg* next;  //下一个消息位置
        void *security;           //真正消息位置
    };

    在/usr/include/linux/msg.h文件中定义了队列大小的限制。不同的Linux版本值不同

    #define MSGMNI 16  //最大消息队列个数
    #define MSGMAX 8192  //消息队列中每个消息最大为8192字节
    #define MSGMNB 16384 //每个消息队列最大为16384字节

    int msgget (key_t __key, int __msgflg):创建消息队列

      第一个参数:由ftok创建的key值

      第二个参数:低位确定消息队列的访问权限,最终值为perm&~umask. ??不懂

                          高位包含 #define IPC_CREAT  00001000    //如果key不存在,则创建,存在返回ID

                                      #define IPC_EXCL  00002000     //如果key存在,返回失败

                                      #define IPC_NOWAIT  00004000  //如果需要等待,直接返回错误

    int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf) :控制消息队列属性

      第一个参数:消息队列标识符,即msgget的返回值

      第二个参数:执行的控制命令,包括

    •     IPC_STAT 2:读取消息队列属性。取得队列的msqid_ds结构,放入第三个参数
    •     IPC_SET 1:设置消息队列属性。只有有效用户ID等于msg_perm.cuid或msg_perm.uid的进程或者超级用户特权进程可以设置。只有超级用户可以增加msg_qbytes。
    •     IPC_RMID: 删除消息队列。立即生效。仍使用这一消息队列的其他进程在下一次试图对此队列操作时,会出错返回EIDRM。同样只有两种用户可以使用该命令。
    •     IPC_INFO: 读取消息队列基本情况

      第三个参数:存储读取或需要修改的消息队列的属性 

    int msgsnd (int __msqid, __const void * __msgp, size_t __msgsz, int __msgflg) :发送信息到消息队列,成功返回0,否则-1.同时msg_qnum递增1,msg_lspid设置为调用进程的进程ID,msg_stime设置为当前时间。

      第一个参数:指定的消息队列标识符

      第二个参数:指向用户定义缓冲区

    struct msgbuf{
          long mtype;       //消息类型
          char mtext[1];   //消息内容,在使用时自己重新定义此结构
    };

      第三个参数:接收信息的大小

      第四个参数:指定达到系统限制时采取的操作。设置为IPC_NOWAIT,在需要等待时立即返回错误EAGAIN;设置为0,阻塞调用进程

    int msgrcv (int __msqid, void *__msgp, size_t __msgsz, long int __msgtyp, int __msgflg) :从队列中取消息

    具体说明太长了,上图:

    例子,发送接收消息,读取限制信息

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<string.h>
    #include<sys/msg.h>
    #define BUFSIZE 128
    struct msg_buf            //自定义消息结构体
    {
        long type;
        char msg[BUFSIZE];
    };
    int main(int argc, char *argv[])
    {
        key_t key;
        int msgid;
        struct msg_buf msg_snd, msg_rcv;
        struct msginfo buf;
        char *ptr = "helloworld";
        memset(&msg_snd, '', sizeof(struct msg_buf));
        memset(&msg_rcv, '', sizeof(struct msg_buf));
        msg_rcv.type = 1;
        msg_snd.type = 1;
        memcpy(msg_snd.msg, ptr, strlen(ptr));
        if((key = ftok(".",'A')) == -1)
        {
            perror("ftok");
            exit(EXIT_FAILURE);
        }
        if((msgid=msgget(key,0600|IPC_CREAT)) == -1)
        {
            perror("msgget");
            exit(EXIT_FAILURE);
        }
        printf("msgsnd_return = %d
    ", msgsnd(msgid,(void *)&msg_snd, strlen(msg_snd.msg), 0));
        msgctl(msgid, MSG_INFO, &buf);
        printf("buf.msgmax=%d
    ", buf.msgmax);
        printf("buf.msgmnb=%d
    ", buf.msgmnb);
        printf("buf.msgpool=%d
    ", buf.msgpool);
        printf("buf.semmap=%d
    ", buf.msgmap);
        printf("buf.msgmni=%d
    ", buf.msgmni);
        printf("buf.msgssz=%d
    ", buf.msgssz);
        printf("buf.msgtql=%d
    ", buf.msgtql);
        printf("buf.msgseg=%d
    ", buf.msgseg);
        
        printf("msgrcv_return = %d
    ", msgrcv(msgid, (void *)&msg_rcv, BUFSIZE,msg_rcv.type,0));
        printf("rev msg:%s
    ", msg_rcv.msg);
        printf("msgctl_return=%d
    ",msgctl(msgid,IPC_RMID,0));
    }

    下面是照书上抄的消息队列实现实时通信的例子

    在我的电脑上无法接收消息????

    send端

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<string.h>
    #include<sys/msg.h>
    struct msgbuf{
        int type;
        char ptr[1024];
    };
    int main(int argc, char *argv[])
    {
        key_t key;
        key = ftok(argv[1], 100);
        int msgid;
        msgid = msgget(key, IPC_CREAT|0600);
        if(msgid == -1)
        {
            perror("msgget");
            exit(EXIT_FAILURE);
        }
        printf("key = %d, msgid = %d
    ", key, msgid);
        pid_t pid;
        pid = fork();
        if(pid == 0)
        {
            struct msgbuf data;  //书上是在while循环里每次malloc,后面free 但是我那样写发现每次msgsnd都失败,说identitier removed
            while(1)
            {
                printf("pls input msg to send:");
                char buf[128];
                fgets(buf, 128, stdin);    
                data.type = 1;
                memcpy(data.ptr, buf, strlen(buf) + 1);
                if(msgsnd(msgid, (void *)&data, strlen(buf) + 1, 0) == -1)
                {
                    perror("msgsnd");
                    exit(EXIT_FAILURE);
                }
                sleep(1);
            }
        }
        else
        {
            struct msgbuf mybuf;
            while(1)
            {
                memset(&mybuf, '', sizeof(mybuf));
                if(msgrcv(msgid, &mybuf, 1024, 2, 0) == -1)
                {
                    perror("msgrcv");
                    exit(EXIT_FAILURE);
                }
                printf("recv msg:%s
    ", mybuf.ptr);
            }
        }
    }

    receive端代码类似,就是发送和接收的信号类型不一样。

  • 相关阅读:
    Handler Looper MessageQueue HandlerThread
    Android屏幕适配
    android开发环境搭建
    Task
    C#语法糖
    Window Phone 开发学习
    Android ListView使用
    网络分析工具
    VS2005在水晶报表中如何显示数据库中保存的是图片路径的图片
    在SQL Server中获取Excel文件中所有Sheet工作表的名称
  • 原文地址:https://www.cnblogs.com/dplearning/p/4686201.html
Copyright © 2011-2022 走看看