进程间通信-消息队列

消息队列(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发送消息:

[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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值