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

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

前述


System V IPC

0a2653c851af460fa595bd959398a8f1.png

特点:

与管道有所不同,它完全使用了不同的实现机制,与文件没任何的关系,也就是说内核不再以文件的形式来管理System V IPC

System V IPC不再以文件的形式存在,因此没有文件描述符这个东西,但是它有类似的“标识符”

任何进程之间通信时,都可以使用System V IPC来通信

POSIX也可以支持消息队列、共享内存、信号量能在unix下运行


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


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


1.1 消息的组成


1.消息编号:识别信息用

2.消息正文:真正的信息内容

0eacb84100b54626af849e6b562bf92a.png


1.2 创建


int msgget(key_t key, int msgflg);


0a2653c851af460fa595bd959398a8f1.png


使用ftok生成key值


0eacb84100b54626af849e6b562bf92a.png2d65d23f6d4748949b924e4057485923.png


1.2 查看系统的消息队列


0a2653c851af460fa595bd959398a8f1.png0eacb84100b54626af849e6b562bf92a.png


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标识的消息队列

0a2653c851af460fa595bd959398a8f1.png

msgctl


0a2653c851af460fa595bd959398a8f1.png0eacb84100b54626af849e6b562bf92a.png2d65d23f6d4748949b924e4057485923.png2e9b90b2ca334476abebe75bafe6eeaa.png


#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;
}

0a2653c851af460fa595bd959398a8f1.png


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


2.1 发送


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

0eacb84100b54626af849e6b562bf92a.png


2.2 接收


ssize_ t msgrcv(int msqid, void *msgp, size_ t msgsz, long msgtyp, int msgflg);

2d65d23f6d4748949b924e4057485923.png


#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 成果展示


2019082413041482.gif

相关文章
|
消息中间件 存储 网络协议
从零开始掌握进程间通信:管道、信号、消息队列、共享内存大揭秘
本文详细介绍了进程间通信(IPC)的六种主要方式:管道、信号、消息队列、共享内存、信号量和套接字。每种方式都有其特点和适用场景,如管道适用于父子进程间的通信,消息队列能传递结构化数据,共享内存提供高速数据交换,信号量用于同步控制,套接字支持跨网络通信。通过对比和分析,帮助读者理解并选择合适的IPC机制,以提高系统性能和可靠性。
2480 14
|
消息中间件 Linux
Linux中的System V通信标准--共享内存、消息队列以及信号量
希望本文能帮助您更好地理解和应用System V IPC机制,构建高效的Linux应用程序。
754 48
|
消息中间件 存储 供应链
进程间通信方式-----消息队列通信
【10月更文挑战第29天】消息队列通信是一种强大而灵活的进程间通信机制,它通过异步通信、解耦和缓冲等特性,为分布式系统和多进程应用提供了高效的通信方式。在实际应用中,需要根据具体的需求和场景,合理地选择和使用消息队列,以充分发挥其优势,同时注意其可能带来的复杂性和性能开销等问题。
|
消息中间件 Linux
Linux:进程间通信(共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)
通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。
1190 20
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
1065 15
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
908 13
|
消息中间件 存储 Linux
|
消息中间件 C语言 RocketMQ
消息队列 MQ操作报错合集之出现"Connection reset by peer"的错误,该如何处理
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
消息中间件 Java C语言
消息队列 MQ使用问题之在使用C++客户端和GBase的ESQL进行编译时出现core dump,该怎么办
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
消息中间件 存储 Kafka
MQ 消息队列核心原理,12 条最全面总结!
本文总结了消息队列的12个核心原理,涵盖消息顺序性、ACK机制、持久化及高可用性等内容。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。