首页 > 系统相关 >linux消息队列

linux消息队列

时间:2023-06-01 18:04:00浏览次数:39  
标签:IPC 函数 队列 int 消息 linux include


经典进程间通信机制(IPC):管道、FIFO、消息队列、信号量以及共享储存。

这些机制允许在同一台计算机上运行的进程可以相互通信。但是当考察到不同计算机(通过网络相连)的进程相互通信时就必须借助网络通信机制(network IPC),在分布式计算环境中,为了集成分布式应用,开发者需要对异构网络环境下的分布式应用提供有效的通信手段。为了管理需要共享的信息,对应用提供公共的信息交换机制是重要的。

消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法,其特点如下:
1)消息队列可以实现消息的随机查询。消息不一定要以先进先出的次序读取,编程时可以按消息的类型读取。
2)消息队列允许一个或多个进程向它写入或者读取消息。
3)与无名管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删除。
4)每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的。
5)消息队列是消息的链表,存放在内存中,由内核维护。只有内核重启或人工删除消息队列时,该消息队列才会被删除。若不人工删除消息队列,消息队列会一直存在于系统中。

1.ftok()

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

函数原型:
key_t ftok( const char * pathname , int proj_id );
参数:

pathname 就时你指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽 然为int,但是只有8个比特被使用(0-255)。
返回值: 成功时候返回key_t 类型的key值,失败返回-1

系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
函数原型:key_t ftok( const char * fname, int id ); (id>0)
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录。

在一般的UNIX实现中,是将文件的索引节点号取出。(文件重建将会分配一个新的索引节点号)
ftok 返回值组成:hex(id)&0xff03 hex(节点号)&0xffff。
传入的id低8位+0x03+ 节点号的低16位。(test on redhat )
可通过 ls -l 查看文件节点值。

示例:

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

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

    key = ftok(".", 2012); // key 值  

    // 创建消息队列  
    msgqid = msgget(key, IPC_CREAT|0666);  

    return 0;  
}

linux消息队列_#include

2.msgget函数

头文件

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

函数原型: int msgget ( key_t key , int msgflg );
函数描述:建立消息队列
参数:
msgget()函数的第一个参数是消息队列对象的关键字(key),函数将它与已有的消息队
列对象的关键字进行比较来判断消息队列对象是否已经创建。而函数进行的具体操作是
由第二个参数,msgflg 控制的。它可以取下面的几个值:
IPC_CREAT :如果消息队列对象不存在,则创建之,否则则进行打开操作;
IPC_EXCL:和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建之,否则产生一个错误并返回。
返回值:
成功时返回队列ID,失败返回-1,错误原因存于error中
EEXIST (Queue exists, cannot create)
EIDRM (Queue is marked for deletion)
ENOENT (Queue does not exist)
ENOMEM (Not enough memory to create queue)
ENOSPC (Maximum queue limit exceeded)

3.msgsnd函数:

头文件

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

函数原型:int msgsnd ( int msgid , struct msgbuf*msgp , int msgsz, int msgflg );

函数描述:将消息送入消息队列

参数说明:
1)msgid
传给msgsnd()函数的第一个参数msqid 是消息队列对象的标识符(由msgget()函数得
到),第二个参数msgp 指向要发送的消息所在的内存,第三个参数msgsz 是要发送信息长度(字节数),可以用以下的公式计算:
msgsz = sizeof(struct mymsgbuf) - sizeof(long);
第四个参数是控制函数行为的标志,可以取以下的值:
0,忽略标志位;
IPC_NOWAIT,如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线
程。如果不指定这个参数,线程将被阻塞直到消息被可以被写入。

2)msgbuf
对于消息队列的读写,都是以消息类型为准。消息类型相当于保险柜号码,A 往 1 号保险柜放东西,对方想取出 A 的东西必须也是从 1 号保险柜里取。同理,某一进程往消息队列添加 a 类型的消息,别的进程要想取出这进程添加的信息也必须取 a 类型的消息。
在学习消息队列读写操作前,我们先学习消息队列的消息格式:

smgbuf结构体定义如下:

struct smgbuf 
 { 
 long mtype; //消息的类型 
 char mtext [x] ; //消息正文,长度由msgsz决定 
 }

消息类型必须是长整型的,而且必须是结构体类型的第一个成员,类型下面是消息正文,正文可以有多个成员(正文成员可以是任意数据类型的)。至于这个结构体类型叫什么名字,里面成员叫什么名字,自行定义,没有明文规定。
3)msgsz:
消息正文的字节数。
4)msgflg:
函数的控制属性,其取值如下:

0:msgsnd() 调用阻塞直到条件满足为止。
IPC_NOWAIT: 若消息没有立即发送则调用该函数的进程会立即返回。

返回: 0 on success
-1 on error: errno = EAGAIN (queue is full, and IPC_NOWAIT was asserted)
EACCES (permission denied, no write permission)
EFAULT (msgp address isn’t accessable – invalid)
EIDRM (The message queue has been removed)
EINTR (Received a signal while waiting to write)
EINVAL (Invalid message queue identifier, nonpositive
message type, or invalid message size)
ENOMEM (Not enough memory to copy message buffer)

4.msgrcv函数

头文件

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

函数定义:int msgrcv( int msgid , struct msgbuf* msgp , int msgsz , long msgtyp, int msgflg);

函数描述:从消息队列中读取消息

参数:
函数的前三个参数和msgsnd()函数中对应的参数的含义是相同的。

第四个参数mtype
指定了函数从队列中所取的消息的类型。函数将从队列中搜索类型与之匹配的消息并将
之返回。不过这里有一个例外。如果mtype 的值是零的话,函数将不做类型检查而自动返回队列中的最旧的消息。第五个参数依然是是控制函数行为的标志,取值可以是:
0,表示忽略;
IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数
的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件
的消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果 进程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。
MSG_NOERROR,如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,
剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不 被取出。
当消息从队列内取出后,相应的消息就从队列中删除了。
msgbuf:结构体,定义如下:

struct msgbuf 
 { 
 long mtype ; //信息种类 
 char mtest[x];//信息内容 ,长度由msgsz指定 
 }

msgtyp: 信息类型。 取值如下:
msgtyp = 0 ,不分类型,直接返回消息队列中的第一项
msgtyp > 0 ,返回第一项 msgtyp与 msgbuf结构体中的mtype相同的信息
msgtyp <0 , 返回第一项 mtype小于等于msgtyp绝对值的信息

msgflg:取值如下:
IPC_NOWAIT ,不阻塞
IPC_NOERROR ,若信息长度超过参数msgsz,则截断信息而不报错。

返回值:
成功时返回所获取信息的长度,失败返回-1,错误信息存于error
Number of bytes copied into message buffer
-1 on error: errno = E2BIG (Message length is greater than
msgsz,no MSG_NOERROR)
EACCES (No read permission)
EFAULT (Address pointed to by msgp is invalid)
EIDRM (Queue was removed during retrieval)
EINTR (Interrupted by arriving signal)
EINVAL (msgqid invalid, or msgsz less than 0)
ENOMSG (IPC_NOWAIT asserted, and no message exists in the queue to satisfy the request)

5.msgctl函数

所需头文件

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

函数说明
获取和设置消息队列的属性

函数原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf)

函数传入值
msqid
消息队列标识符

cmd 指令

IPC_STAT:获得msgid的消息队列头数据到buf中
IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes
buf:消息队列管理结构体,请参见消息队列内核结构说明部分

函数返回值
成功:0
出错:-1,错误原因存于error中
错误代码
EACCESS:参数cmd为IPC_STAT,确无权限读取该消息队列
EFAULT:参数buf指向无效的内存地址
EIDRM:标识符为msqid的消息队列已被删除
EINVAL:无效的参数cmd或msqid
EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

对于消息队列的操作,我们可以类比为这么一个过程:假如 A 有个东西要给 B,因为某些原因 A 不能当面直接给 B,这时候他们需要借助第三方托管(如银行),A 找到某个具体地址的建设银行,然后把东西放到某个保险柜里(如 1 号保险柜),对于 B 而言,要想成功取出 A 的东西,必须保证去同一地址的同一间银行取东西,而且只有 1 号保险柜的东西才是 A 给自己的。

对于上面的例子,涉及到几个比较重要的信息:地址、银行、保险柜号码。
只有同一个地址才能保证是同一个银行,只有是同一个银行双方才能借助它来托管,只有同一个保险柜号码才能保证是对方托管给自己的东西。

而在消息队列操作中,键(key)值相当于地址,消息队列标示符相当于具体的某个银行,消息类型相当于保险柜号码。
同一个键(key)值可以保证是同一个消息队列,同一个消息队列标示符才能保证不同的进程可以相互通信,同一个消息类型才能保证某个进程取出是对方的信息。

示例:

//发送端程序

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

#define MAX_TEXT 512   //定义text大小
struct msg_st          //定义消息结构体
{  
    long int msg_type;  // msgtyp > 0 ,返回第一项 msgtyp与 msgbuf结构体中的mtype相同的信息
    char text[MAX_TEXT];  
};  

int main()
{  
    int running = 1;      //运行标志位
    struct msg_st data;  //msg_st结构体
    char buffer[BUFSIZ];   //定义缓冲区,BUFSIZ为库中定义大小
    int msgid = -1;       //消息队列对象的标识符

    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);  //创建消息队列关键字为1234,权限为666,如果消息队列对象不存在,则创建之,否则则进行打开操作;返回标识符msgid
    if(msgid == -1)    //错误
    {  
        fprintf(stderr, "msgget failed with error: %d\n", errno);  
        exit(EXIT_FAILURE);  
    }  

    //向消息队列中写消息,直到写入end  
    while(running)           //运行标志位是1时循环执行
    {  

        printf("Enter some text: ");   //提示输入数据  
        fgets(buffer, BUFSIZ, stdin);  //stdin是标准输入,一般指键盘输入到缓冲区里的东西。
        data.msg_type = 1;    
        strcpy(data.text, buffer);    //buffer里的数据复制到data

        if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)   //向队列发送数据  
        {  
            fprintf(stderr, "msgsnd failed\n");    //错误
            exit(EXIT_FAILURE);  
        }  
        //输入end结束输入  
        if(strncmp(buffer, "end", 3) == 0)  
            running = 0;  
        sleep(1);  
    }  
    exit(EXIT_SUCCESS);  
}

//接收端程序

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

struct msg_st
{  
    long int msg_type;  
    char text[BUFSIZ];  
};  

int main()  
{  
    int running = 1;  
    int msgid = -1;  
    struct msg_st data;  
    long int msgtype = 0; //注意1 msgtyp = 0 ,不分类型,直接返回消息队列中的第一项


    //建立消息队列  
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);   //和发送程序相同。创建消息队列关键字为1234,权限为666,如果消息队列对象不存在,则创建之,否则则进行打开操作;返回标识符msgid。标识符都为1234
    if(msgid == -1)  
    {  
        fprintf(stderr, "msgget failed with error: %d\n", errno);  
        exit(EXIT_FAILURE);  
    }  
    //从队列中获取消息,直到遇到end消息为止  
    while(running)  
    {  
        if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)  //
        {  
            fprintf(stderr, "msgrcv failed with errno: %d\n", errno);  
            exit(EXIT_FAILURE);  
        }  
        printf("You wrote: %s\n",data.text);  //打印data.text
        //遇到end结束  
        if(strncmp(data.text, "end", 3) == 0)  
            running = 0;  
    }  
    //删除消息队列  
    if(msgctl(msgid, IPC_RMID, 0) == -1)  
    {  
        fprintf(stderr, "msgctl(IPC_RMID) failed\n");  
        exit(EXIT_FAILURE);  
    }  
    exit(EXIT_SUCCESS);  
}


标签:IPC,函数,队列,int,消息,linux,include
From: https://blog.51cto.com/u_16147764/6397234

相关文章

  • VMware中安装Linux-kali
    VMware中安装Linux-kali(详细图文教程)萌褚于2022-05-2010:33:30发布9499收藏94文章标签:Linux版权华为云开发者联盟该内容已被华为云开发者联盟社区收录加入社区镜像下载、域名解析、时间同步请点击阿里云开源镜像站一,VMware配置。  因为要装kali,所以要用到Debian......
  • Linux进程管理、计划任务笔记
    一、Linux进程管理1.1、进程概念进程是正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说CPU(寄存器),IO,内存,网络资源等。并发程序和顺序程序有本质上的差别,为了能更好地描述程序的并发执行,实现操作系统的并发性和共享性,引入“进程”的概念。进程是具有一定独立......
  • Linux系统管理---时区和时间管理
    一、时区查看时区:cat/etc/sysconfig/clock时区存放文件:/etc/localtime修改时区:cp/usr/share/zoneinfo/Asia/Shanghai /etc/localtime修改验证:date  返回有CST,表示修改正确了二、时间查看时间:date 或者  date-R或者按指定格式:date"+%Y-%m-%d%H:%M:%S"[root@hadoo......
  • Linux软件安装--二进制发布包安装、rpm发布包安装(案例:jdk和mysql安装)
    Linux软件安装的4种方式一、二进制发布包指软件已经根据平台编译并且打包,拿到这个包后解压并配置环境变量,如jdk包、mysql包、Tomcat包。示例:二进制发布包安装jdk。示例:二进制发布包安装jdk1.获取安装包1).直接从linux网上下载安装包-->wget https://download.oracle.com/otn-pu......
  • Linux的SSH免密登录配置
    一、SSH概念SSH为SecureShell(安全外壳协议)的缩写,简单说,SSH只是一种网络协议,用于计算机之间的加密登录传输,很多ftp、pop和telnet在本质上都是不安全的,因为它们在网络上用明文传送口令和数据,别有用心的人非常容易就可以截获这些口令和数据。而SSH就是专为远程登录会话和其他网络服务......
  • linux配置静态ip
    转:https://blog.csdn.net/weixin_46560589/article/details/1248148601进入配置文件目录cd/etc/sysconfig/network-scripts 2编辑配置文件vimifcfg-ens32ens32是虚拟网卡名称,根据自己虚机上的网卡名称修改如果有多个网卡,编辑你要用的那个网卡 3......
  • linux 中 删除指定匹配特定字符指定次数之前或者之后的内容
     001、[root@PC1test]#lsa.txt[root@PC1test]#cata.txt0102030405060708091011121314151617181920[root@PC1test]#sed's//tag/2'a.txt|sed's/.*tag//'##删除第二个空格之前的所有内容030405080910131415181920......
  • linux下查看 SELinux状态及关闭SELinux
    SELinux全称为安全增强式Security-EnhancedLinux(SELinux),是一个在内核中实践的强制存取控制(MAC)安全性机制。SELinux首先在CentOS4出现,并在其后的CentOS发行版本获得重大改善。这些改善代表用SELinux解决问题的方法亦随著时间而改变。SELinux的原理与架构SELinux的整体......
  • Linux centos7 ppc64le编译安装MySQL8遇见问题
    一.关于Nopackagedevtoolset-7-gccavailable.的解决办法1.使用centos默认yum源2.依次执行以下命令yuminstall-ycentos-release-sclyuminstall-ydevtoolset-7 二.cmake3>=3.6.1isneededbymysql-community-8.0.18-1.el7.ppc64le安装cmake3yuminstall......
  • 分布式队列编程:模型、实战
    介绍作为一种基础的抽象数据结构,队列被广泛应用在各类编程中。大数据时代对跨进程、跨机器的通讯提出了更高的要求,和以往相比,分布式队列编程的运用几乎已无处不在。但是,这种常见的基础性的事物往往容易被忽视,使用者往往会忽视两点:使用分布式队列的时候,没有意识到它是队列。有具体需......