进程间通信-消息队列

场景:同一台linux设备下,多个进程之间数据要互相通信,就可以使用消息队列进行数据传输。

 

消息队列(Message Queue):是消息的链表,存放在内核中并由消息队列标识符标识

  • 优点:可以实现任意进程间的通信,并通过系统调用函数来实现消息发送和接收之间的同步,无需考虑同步问题,方便
  • 缺点:信息的复制需要额外消耗 CPU 的时间,不适宜于信息量大或操作频繁的场合

消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接收者接受的数据块可以有不同的类型。

 

消息队列函数:

1、msgget
功能:创建和访问一个消息队列
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflag);
参数:
key:消息队列名称,用ftok()产生
msgflag:IPC_CREAT或者IPC_EXCL,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。
返回值:成功返回非负整数,即消息队列的标识码,失败返回-1

 

2、ftok
功能:创建消息队列名称
原型:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
返回值:成功返回一个key值,用于创建消息队列,失败返回-1
3、msgctl
功能:消息队列的控制函数
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
mgqid:由msgget函数返回的消息队列标识
cmd:命令,这边有三个命令
IPC_STAT把msqid_ds结构中的数据设置为消息队列的当前关联值
IPC_SET在进程有足够权限的前提下,把消息队列的当前值设置为msqid_ds数据结构中给出的值
IPC_RMID删除消息队列
返回值:成功返回0,失败返回-1
4、msgsnd
功能:把一条消息添加到消息队列中
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msgid:msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息
msgsz:msgp指向的消息的长度
msgflg:默认为0
返回值:成功返回0,失败返回-1
发送的消息结构:
struct msgbuf
{
     long mtye;
     char mtext[1];
};
5、msgrcv
功能:从一个消息队列接收消息
原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:
msgid:msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息
msgsz:msgp指向的消息的长度
msgtyp:消息类型
type==0,返回队列中第一个消息
type > 0, 返回队列中消息类型为type的第一个消息
type < 0, 返回队列中消息类型值小于或等于type绝对值的消息,如果这种消息有若干个,则取类型值最小的消息
msgflg:默认为0

上源码:

//comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
struct msgbuf
{
    long mtype;
    char mtext[1024];
};
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
int createMsgQueue();
int getMsgQueue();
int destoryMsgQueue(int msg_id);
int sendMsgQueue(int msg_id, int who, char *msg);
int recvMsgQueue(int msg_id, int recvType, char out[]);
#endif
//comm.c
#include "comm.h"
static int commMsgQueue(int cmd)
{
    key_t key = ftok("/tmp", 0x6666);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    int msg_id = msgget(key, cmd);
    if(msg_id < 0)
    {
        perror("msgget");
    }
    return msg_id;
}
int createMsgQueue()
{
    return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}
int getMsgQueue()
{
    return commMsgQueue(IPC_CREAT);
}
int destoryMsgQueue(int msg_id)
{
    if(msgctl(msg_id, IPC_RMID, NULL) < 0)
    {
        perror("msgctl");
        return -1;
    }
    return 0;
}
int sendMsgQueue(int msg_id, int type, char *msg)
{
    struct msgbuf buf;
    buf.mtype = type;
    strcpy(buf.mtext, msg);
    if(msgsnd(msg_id, (void*)&buf, sizeof(buf.mtext), 0) < 0)
    {
        perror("msgsnd");
        return -1;
    }
    return 0;
}
int recvMsgQueue(int msg_id, int recvType, char out[])
{
    struct msgbuf buf;
    int size = sizeof(buf.mtext);
    if(msgrcv(msg_id, (void *)&buf, size, recvType, 0) < 0)
    {
        perror("msgrcv");
        return -1;
    }
    strncpy(out, buf.mtext, size);
    out[size] = 0;
    return 0;
}
//server.c
#include "comm.h"
int main()
{
    int msgid = createMsgQueue();
    printf("msgid = %d\n", msgid);
    char buf[1024] = {0};
    while(1)
    {
        recvMsgQueue(msgid, CLIENT_TYPE, buf);
        if(strcasecmp("quit", buf) == 0)
            break;
        printf("client:%s\n", buf);
        /*
        printf("Please enter:");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf));
        if(s > 0)
        {
            buf[s - 1] = 0;
            sendMsgQueue(msgid, SERVER_TYPE, buf);
            printf("send done, wait recv...\n");
        }
        */
    }
    destoryMsgQueue(msgid);
    return 0;
}
//client.c
#include "comm.h"
int main()
{
    int msgid = getMsgQueue();
    printf("msgid:%d\n", msgid);
    char buf[1024] = {0};
    while(1)
    {
        printf("Please Enter:");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf));
        if(s > 0)
        {
            buf[s - 1] = 0;
            sendMsgQueue(msgid, CLIENT_TYPE, buf);
            if(strcasecmp("quit", buf) == 0)
                break;
            //printf("send done, wait recv...\n");
        }
        //recvMsgQueue(msgid, SERVER_TYPE, buf);
        //printf("server#%s\n", buf);
    }
    return 0;
}

编译执行client、server。

client发送消息:

[root@livedvd tmp]# ./client

msgid:360448

Please Enter:AAAA

Please Enter:BBBBB

Please Enter:HEIIL

Please Enter:quit

[root@livedvd tmp]#

 

server接收消息:

[root@livedvd tmp]# ./server

msgid = 360448

client:AAAA

client:BBBBB

client:HEIIL

[root@livedvd tmp]#

 

ipcs -q :查看IPC资源

ipcrm -q:删除IPC资源

 

参考:

https://blog.csdn.net/wei_cheng18/article/details/79661495

https://www.cnblogs.com/nufangrensheng/p/3561820.html

https://blog.csdn.net/guoping16/article/details/6584024

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值