嵌入式Linux C进程间通信(三)——消息队列

前述

System V IPC
在这里插入图片描述
特点:
与管道有所不同,它完全使用了不同的实现机制,与文件没任何的关系,也就是说内核不再以文件的形式来管理System V IPC
System V IPC不再以文件的形式存在,因此没有文件描述符这个东西,但是它有类似的“标识符”
任何进程之间通信时,都可以使用System V IPC来通信
POSIX也可以支持消息队列、共享内存、信号量能在unix下运行

一、消息队列的创建和删除

消息队列的本质就是由内核创建的用于存放消息的链表,由于是存放消息的,所以我们就把这个链表称为消息队列。

1.1 消息的组成

  1. 消息编号:识别信息用
  2. 消息正文:真正的信息内容
    在这里插入图片描述

1.2 创建

int msgget(key_t key, int msgflg);
在这里插入图片描述

使用ftok生成key值
在这里插入图片描述
在这里插入图片描述

1.2 查看系统的消息队列

在这里插入图片描述
在这里插入图片描述

1.3 消息队列的创建

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

#define MSGNAME "./msg_file"

int main(int argc, char const *argv[])
{
    key_t key;
    int msgid;

    key = ftok(MSGNAME, 'k');

    msgid = msgget(key, IPC_CREAT | 0655);
    if (msgid < 0)
    {
        perror("msgid error!");
        exit(1);
    }
    printf("msgid = %d\n",msgid);

    return 0;
}

1.4 获取属性及删除

进程结束时,system v ipc不会自动删除,进程结束后,使用ipcs依然能够查看到

长方形
重启OS
使用ipcrm命令删除
int msgctl 参数:int mspid,int cmd,struct mspid_ds *buf
ipcrm -Q msgkey移除用msqkey创建的消息队列
ipcrm -q msqid移除用msqid标识的消息队列

在这里插入图片描述
msgctl
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

#define MSGNAME "./msg_file"

int main(int argc, char const *argv[])
{
    key_t key;
    int msgid;

    key = ftok(MSGNAME, 'k');

    msgid = msgget(key, IPC_CREAT | 0655);
    if (msgid < 0)
    {
        perror("msgid error!");
        exit(1);
    }
    printf("key = %x\n", key);
    printf("msgid = %d\n", msgid);

    msgctl(msgid,IPC_RMID,NULL);
    return 0;
}

在这里插入图片描述

二、消息队列的发送和接收

2.1 发送

int msgsnd(int msqid,const void *msgp, size_t msgsz,int msgflg);
在这里插入图片描述

2.2 接收

ssize_ t msgrcv(int msqid, void *msgp, size_ t msgsz, long msgtyp, int msgflg);
在这里插入图片描述

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

#define MSGNAME "./msg_file"

int msgid;

struct msgbuf
{
    long mtype;
    char mtext[1024];
};

void my_exit(int msg)
{
    msgctl(msgid,IPC_RMID,NULL);
}

int main(int argc, char const *argv[])
{
    key_t key;
    pid_t pid;
    signal(SIGINT, my_exit);

    key = ftok(MSGNAME, 'k');

    msgid = msgget(key, IPC_CREAT | 0655);

    if (msgid < 0)
    {
        perror("msgid error!");
        exit(1);
    }
    printf("key = %x\n", key);
    printf("msgid = %d\n", msgid);

    pid = fork();
    if (pid < 0)
    {
        perror("fork perror!\n");
        exit(1);
    }
    if (pid == 0)
    {
        long mtype;
        char buffer[1024];
        struct msgbuf pmsgbuf;
        while (1)
        {
            memset(buffer, 0, sizeof(buffer));
            memset(&pmsgbuf, 0, sizeof(struct msgbuf));
            printf("Please input send msg:\n");
            scanf("%s", buffer);
            strcpy(pmsgbuf.mtext, buffer);
            printf("Please input send msg id:\n");
            scanf("%ld", &mtype);
            pmsgbuf.mtype = mtype;

            if(msgsnd(msgid,(void *)&pmsgbuf,sizeof(pmsgbuf),IPC_NOWAIT) < 0)
            {
                perror("msg snd error!");
                exit(1);
            }
        }
    }
    else if(pid > 0)
    {
        size_t size;
        long mtype;
        char buffer[1024];
        struct msgbuf pmsgbuf;
        while (1)
        {
            memset(buffer, 0, sizeof(buffer));
            memset(&pmsgbuf, 0, sizeof(struct msgbuf));
            size = msgrcv(msgid, &pmsgbuf,sizeof(pmsgbuf),3,0);

            if (size < 0)
            {
                perror("msg rcv error!");
                exit(1);
            }
            printf("recv data:%s\n", pmsgbuf.mtext);
            sleep(1);
        }
    }
    

    
    return 0;
}

在这里插入图片描述

三、任意进程通信及特点

多个进程是如何共享到同一个消息队列?

  1. fork前创建
  2. 创建者把ID保存到某文件,共享进程读出ID即可+
  3. 使用ftok函数,利用与创建者相同的“路径名”和8位整形数,生成相同的key值

消息队列的特点

  1. 传送有格式的消息流
  2. 多进程网状旁叉通信时,消息队列是上上之选
  3. 能实现大规模数据的通信

3.1 msg_read.c

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

#define MSGNAME "./msg_file"

struct msgbuf
{
    long mtype;
    char mtext[1024];
};


int main(int argc, char const *argv[])
{
    key_t key;

    key = ftok(MSGNAME, 'k');

    int msgid = msgget(key, IPC_CREAT | 0777);

    if (msgid < 0)
    {
        perror("msgid error!");
        exit(1);
    }
    printf("key = %x\n", key);
    printf("msgid = %d\n", msgid);
    size_t size;
    long mtype;
    char buffer[1024];
    struct msgbuf pmsgbuf;
    while (1)
    {
        memset(buffer, 0, sizeof(buffer));
        memset(&pmsgbuf, 0, sizeof(struct msgbuf));
        size = msgrcv(msgid, &pmsgbuf,sizeof(pmsgbuf),3,0);

        if (size < 0)
        {
            perror("msg rcv error!");
            exit(1);
        }
        printf("recv data:%s\n", pmsgbuf.mtext);
        sleep(1);
    }
}

3.2 msg_write.c

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

#define MSGNAME "./msg_file"

struct msgbuf
{
    long mtype;
    char mtext[1024];
};


int main(int argc, char const *argv[])
{
    key_t key;

    key = ftok(MSGNAME, 'k');

    int msgid = msgget(key, 0777 | IPC_CREAT);

    if (msgid < 0)
    {
        perror("msgid error!");
        exit(1);
    }
    printf("key = %x\n", key);
    printf("msgid = %d\n", msgid);
    size_t size;
    long mtype;
    char buffer[1024];
    struct msgbuf pmsgbuf;
    while (1)
    {
        memset(buffer, 0, sizeof(buffer));
        memset(&pmsgbuf, 0, sizeof(struct msgbuf));
        printf("Please input send msg:\n");
        scanf("%s", buffer);
        strcpy(pmsgbuf.mtext, buffer);
        printf("Please input send msg id:\n");
        scanf("%ld", &mtype);
        pmsgbuf.mtype = mtype;

        if(msgsnd(msgid,(void *)&pmsgbuf,sizeof(pmsgbuf),IPC_NOWAIT) < 0)
        {
            perror("msg snd error!");
            exit(1);
        }
    }
}

3.3 成果展示

请添加图片描述

posted @ 2022-08-11 17:01  周末不下雨  阅读(136)  评论(0编辑  收藏  举报