Linux进程入门学习(八)-消息队列通信

1.什么是消息队列

消息队列(也叫做报文队列)是一个消息的链式队列。
可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息

2.消息队列特性

1)消息队列是IPC 对象中的一种,消息队列中可以通过唯一的ID 来识别
2)消息队列就是一个消息列表,用户可以在消息队列中添加消息、读消息
3)消息队列可以按照类型来发送/接收信息

消息队列查看:ipcs -q
删除消息队列:ipcrm -q msqid
ipcrm -Q key

3.消息队列的结构

与消息队列相关的数据结构主要有两个:
1)msqid_ds 消息队列数据结构,用来标识整个消息队列的情况
2)msg 消息队列数据结构,是整个消息队列的主体
这里写图片描述
这里写图片描述

kernel 中描述消息链表每个节点结构的结构体是

struct msg {
    struct msg *msg_next; 指向消息链表中下一个节点的指针
    long msg_type; 和msgbuf 中mtype 成员的意义是一样的。
    char *msg_spot; /* message text address */
    time_t msg_stime; /* msgsnd time */
    short msg_ts; /* message text size */
};

kernel 中描述消息的结构体
这里写图片描述

事实上,在我们自定义的结构中,和它对应的部分可以是任意的数据类型,甚至是多个数据类型的集合。
比如我们可以定义这样的一个消息类型:

struct my_msgbuf {
    long mtype; /* Message type */
    long request_id; /* Request identifier */
    struct client info; /* Client information structure */
};

由此可见消息队列在传送消息上的灵活性。

4.消息队列使用步骤

  1. 创建并打开消息队列—— msgget
  2. 写消息队列操作—— msgsnd
  3. 读消息队列操作—— msgrcv
  4. 销毁消息队列—— msgctl

msgget 函数

功能:用于获取消息队列ID
头文件#include <sys/msg.h>
函数原型int msgget(key_t key, int msgflg);
返回值

成功:消息队列ID;
失败:-1

参数列表

key_t key:消息队列的key 值
(可以自己写一个正整数,如IPC_PRIVATE也可以调用函数ftok 来获取)
int msgflg:消息队列的访问权限
可以通过IPC_CREAT 创建:IPC_CREAT | 0666(可读可写)

示例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char *argv[])
{
    int msqid;
    msqid = msgget(IPC_PRIVATE, 0666);
    if(msqid < 0)
    {
        printf("fail to get message \n");
        return -1;
    }
    printf("success to get message, id = %d \n",msqid);
    /* 查看消息队列的创建情况*/
    system("ipcs -q");
    return 0;
}

ftok 函数

功能:用于获取一个key 值
头文件

#include <sys/types.h>
#include <sys/ipc.h>

函数原型

key_t ftok(const char *pathname, int proj_id);

返回值

成功:key 值;
失败:-1

参数列表

const char *pathname:路径:"."
int proj_id:给定的一个正整数

示例:利用ftok 函数生成key 值

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char *argv[])
{
    int msqid;
    key_t key;
    key = ftok("/key", 'a');
    if(key < 0)
    {
        printf("fait to creat key value \n");
        return -1;
    }
    msqid = msgget(key, IPC_CREAT|0666);
    if(msqid < 0)
    {
        printf("fail to get message \n");
        return -1;
    }
    printf("success to get message, id = %d \n",msqid);
    /* 查看消息队列的创建情况*/
    system("ipcs -q");
    return 0;
}

msgctl 函数

功能:用于消息队列控制
头文件

#include <sys/msg.h>

函数原型

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

返回值

成功:0;失败:-1

参数列表

int msqid:消息队列ID
int cmd :IPC_RMID 删除消息队列
struct msqid_ds *buf:消息队列缓冲区如果有IPC_RMID,就设置NULL

示例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char *argv[])
{
    int msqid;
    int ret;
    key_t key;
    key = ftok("/key", 'a');
    if(key < 0)
    {
        printf("fait to creat key value \n");
        return -1;
    }
    msqid = msgget(key, IPC_CREAT|0666);
    if(msqid < 0)
    {
        printf("fail to get message \n");
        return -1;
    }
    printf("success to get message, id = %d \n",msqid);
    /* 查看消息队列的创建情况*/
    system("ipcs -q");
    //新添加内容: 删除消息队列
    ret = msgctl(msqid, IPC_RMID, NULL);
    if(ret < 0)
    {
        printf("fail to delete message queue \n");
        return -1;
    }
    system("ipcs -q");
    return 0;
}

msgsnd 函数

功能:用于消息发送
头文件

#include <sys/msg.h>

函数原型

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

返回值

成功:0;失败:-1

参数列表

int msqid :消息队列ID
const void *msgp:指向发送消息的指针
struct mymsg {
long mtype; /* Message type.消息类型*/
char mtext[1]; /* Message text.消息数据*/
}
size_t msgsz:发送消息大小
int msgflg:消息标志
IPC_NOWAIT:消息没有发送完成也会立即返回
0 :直到消息发送完成再返回

msgrcv 函数

功能:用于消息接收
头文件

#include <sys/msg.h>

函数原型

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

返回值

成功:读取到的消息的大小;失败:-1

参数列表

int msqid:消息队列ID
void *msgp:指向接收消息的指针
struct mymsg {
long mtype; /* Message type.消息类型*/
char mtext[1]; /* Message text.消息数据*/
}
size_t msgsz:接收消息大小
long msgtyp:接受消息的类型
0:接收消息队列中的第一个消息
>0: 接受消息队列中的对应的消息类型
<0: 接收消息队列类型中不小于msgtyp 绝对值消息
int msgflg:消息标志
0:直到消息接收完成再返回
IPC_NOWAIT:消息没有接收完成也会立即返回

示例:

xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ cat msgsnd.c 
/**************************************************************************
* File Name: msgsnd.c
* Author: Po Xie
* E-mail: 2446603068@qq.com
* Create Time: Wed 09 Aug 2017 04:33:40 AM PDT
***************************************************************************/

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

#define MAX_MSG 128

struct msgbuf
{
    long type;
    char buf[MAX_MSG];
};

int main(int argc, char **argv)
{
    int msgid;
    int err;
    int cnt;

    key_t key;
    key = ftok("./key",'b');
    if(key < 0)
    {
        printf("fail to create key value\n");
        return -1;
    }
    msgid = msgget(key, IPC_CREAT|0666);
    if(key < 0)
    {

        printf("fail to get message \n");
        return -1;
    }
    printf("success to get message \n");

    system("ipcs -q");

    //添加写操作
    struct msgbuf sendbuf,recvbuf;
    sendbuf.type = 100;
    printf("please enter you message: \n");
    fgets(sendbuf.buf, MAX_MSG, stdin);

    err = msgsnd(msgid, (void *)&sendbuf, strlen(sendbuf.buf), 0);
    if(err < 0)
    {
        printf("write message fail \n");
        return -1;
    }
    printf("success to write message \n");
    printf("err = %d\n",err);

    system("ipcs -q");

    //添加读操作
    memset(recvbuf.buf, 0, MAX_MSG);
    cnt = msgrcv(msgid, (void *)&recvbuf, MAX_MSG, 100, 0);
    if(cnt < 0)
    {
        printf("fail to receive message ");
        return -1;
    }
    printf("success to receive message, cnt=%d \n",cnt);
    printf("read data = %s\n",recvbuf.buf);

    //测试第二次是否还可以读(不可以,会阻塞)
    msgrcv(msgid, (void *)&recvbuf, MAX_MSG, 100, 0);
    printf("second read data =%s\n",recvbuf.buf);
    //删除消息队列
    err = msgctl(msgid, IPC_RMID, NULL);
    if(err < 0)
    {
        printf("fail to delete message queue \n");
        return -1;

    }
    system("ipcs -q");
    return 0;
}

运行结果:

xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ ./msgsnd
success to get message 

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x62270166 0          xie        666        0            0           

please enter you message: 
hello world, hello linux!
success to write message 
err = 0

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x62270166 0          xie        666        26           1           

success to receive message, cnt=26 
read data = hello world, hello linux!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值