Linux系统编程64 进程,线程间通信2 - 消息队列
发布日期:2021-05-07 13:26:04 浏览次数:20 分类:精选文章

本文共 5957 字,大约阅读时间需要 19 分钟。

XSI -> SysV

IPC -> Inter process communication 进程间通信的三种机制主动端:先发包的一方被动端:先收包的一方 ,一定是被动端先运行 等着收包mhr@ubuntu:~/Desktop/xitongbiancheng/communication$ ipcsMessage Queues 消息队列 ,双工key        msqid      owner      perms      used-bytes   messages msgget();msgop();msgctl();Shared Memory Segments 信号量数组key        shmid      owner      perms      bytes      nattch     status  Semaphore Arrays  共享内存key        semid      owner      perms      nsems

关于 key值:

在这里插入图片描述

key:ftok(),产生IPC Key值,将路径名和项目标识符转换为System V IPC密钥

NAME       ftok - convert a pathname and a project identifier to a System V IPC keySYNOPSIS       #include 
#include
key_t ftok(const char *pathname, int proj_id);

其中参数fname是指定的文件名,这个文件必须是存在的而且可以访问的。id是子序号,它是一个8bit的整数。即范围是0~255。当函数执行成功,则会返回key_t键值,否则返回-1。在一般的UNIX中,通常是将文件的索引节点取出,然后在前面加上子序号就得到key_t的值。

msgget(): 用来创建新的消息队列或获取已有的消息队列

NAME       msgget - get a System V message queue identifier 获取一个消息队列的IDSYNOPSIS       #include 
#include
#include

/*

key: 消息队列key值,函数将它与已有的消息队列对象的关键字进行比较来判断消息队列对象是否已经创建
msgflg : 创建当前消息队列的特殊指定

IPC_CREAT:如果消息队列对象不存在,则创建之,否则则进行打开操作;IPC_EXCL:和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建,否则产生一个错误并返回。

*/

int msgget(key_t key, int msgflg);RETURN VALUE       If successful, the return value will be the message queue identifier (a nonnegative integer), otherwise -1 with errno indicating the error.

如果单独使用IPC_CREAT 标志,msgget()函数要么返回一个已经存在的消息队列对象的标识符,要么返回一个新建立的消息队列对象的标识符。如果将IPC_CREAT 和IPC_EXCL标志一起使用,msgget()将返回一个新建的消息对象的标识符,或者返回-1 如果消息队列对象已存在。IPC_EXCL 标志本身并没有太大的意义,但和IPC_CREAT 标志一起使用可以用来保证所得的消息队列对象是新创建的而不是打开的已有的对象

msgsnd(),msgrcv() : 发送 接受 消息队列

NAME       msgrcv, msgsnd - System V message queue operationsSYNOPSIS       #include 
#include
#include
//发送/*msqid:消息队列IDmsgp :待发送数据位置msgsz :待发送数据大小msgflg :特殊要求*/ int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);//接收/*msqid:消息队列IDmsgp :收取消息存放位置,注意空间格式msgsz :真正收取有效数据信息的大小,而不是全部的数据信息大小:sizeof(rbuf)-sizeof(long)msgtyp:是否挑选消息来接收,比如接收第几个包,所以msg消息队列本质上已经不算是队列了,因为队列一定是先进先出。msgflg:特殊指定操作*/ ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);注意: The msgp argument is a pointer to a caller-defined structure of the following general form: struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ };RETURN VALUE On failure both functions return -1 with errno indicating the error, otherwise msgsnd() returns 0 and msgrcv() returns the number of bytes actually copied into the mtext array.

msgctl():控制一个消息队列,如销毁,设置等等

NAME       msgctl - System V message control operationsSYNOPSIS       #include 
#include
#include
/* 对消息队列msqid 执行 cmd命令,buf表示是否需要传参cmd:IPC_STATIPC_SETIPC_RMID 删除当前消息队列IPC_INFO (Linux-specific)MSG_INFO (Linux-specific)MSG_STAT (Linux-specific)*/ int msgctl(int msqid, int cmd, struct msqid_ds *buf);

实验:进程间通信 – 消息队列, 这里是无亲缘关系的进程间通信。当然了,有亲缘关系的进程也可以使用消息队列通信。

proto.h

#ifndef PROTP_H_#define PROTO_H_#define KEYPATH "/etc/services"#define KEYPROJ 'g'#define NAMESIZE 32struct msg_st{ long mtype;// 仿照   struct msgbuf 	char name[NAMESIZE];	int math;	int chinese;};#endif

rcver.c 接收端进程

#include 
#include
#include
#include
#include
#include
#include
#include "proto.h"int main(void){ key_t key; int msgid; struct msg_st rbuf; key = ftok(KEYPATH,KEYPROJ);//获取IPC 键值 if(key < 0) { perror("ftok"); exit(1); } msgid = msgget(key,IPC_CREAT|0600); //创建 消息队列 返回IP if(msgid < 0) { perror("msgget"); exit(1); } while(1) { //从目标消息队列 接受数据,注意接收数据的大小是有效数据的大小 if(msgrcv(msgid,&rbuf,sizeof(rbuf)-sizeof(long),0,0) < 0) { perror("msgrcv"); exit(1); } printf("NAME = %s\n",rbuf.name); printf("MATH = %d\n",rbuf.math); printf("CHINESE = %s\n",rbuf.chinese); } msgctl(msgid,IPC_RMID,NULL);//销毁消息队列 exit(0);}

snder.c 发送端进程

#include 
#include
#include
#include
#include
#include
#include
#include
#include "proto.h"int main(){ key_t key; int msgid; struct msg_st sbuf; key = ftok(KEYPATH,KEYPROJ);//获取消息队列 IPC 键值 if(key < 0) { perror("ftok"); exit(1); } msgid = msgget(key,0);//获得已创建好的目标消息队列 的 ID if(msgid < 0) { perror("msgget"); exit(1); }//初始化数据 sbuf.mtype = 1; strcpy(sbuf.name,"MHR"); sbuf.math = rand()%100; sbuf.chinese = rand()%100;// 发送数据 if(msgsnd(msgid,&sbuf,sizeof(sbuf)-sizeof(long),0) < 0) { perror("msgsnd"); exit(1); } puts("OK"); exit(0); }

需要注意的是,如果先执行 10次 发送端进程,再执行一次接收端进程,那么接收端会一次性接受 之前10次的 发送端发送的数据。这是因为

消息队列有一个缓存消息的能力,具体能缓存多大的数据,可以 ulimit -a 查看

mhr@ubuntu:~/Desktop/xitongbiancheng/communication/msg/basic$ ulimit -a...POSIX message queues     (bytes, -q) 819200...mhr@ubuntu:~/Desktop/xitongbiancheng/communication/msg/basic$

ipcs 查看当前IPC

ipcrm : ipcrm - remove certain IPC resources 删除指定IPC 参数入下

如 删除指定 消息队列:

先查看 目标消息队列 id

mhr@ubuntu:~/Desktop/xitongbiancheng/communication/msg/basic$ ipcs
------ Message Queues --------
key msqid owner perms used-bytes messages
0x670100d2 0 mhr 600 0 0

删除:

mhr@ubuntu:~/Desktop/xitongbiancheng/communication/msg/basic$ ipcrm -q 0

OPTIONS

-M, --shmem-key shmkey          Remove the shared memory segment created with shmkey after the last detach is performed.   -m, --shmem-id shmid          Remove the shared memory segment identified by shmid after the last detach is performed.   -Q, --queue-key msgkey          Remove the message queue created with msgkey.   -q, --queue-id msgid          Remove the message queue identified by msgid.   -S, --semaphore-key semkey          Remove the semaphore created with semkey.   -s, --semaphore-id semid          Remove the semaphore identified by semid.   -V, --version          Display version information and exit.   -h, --help          Display help text and exit.
上一篇:Linux系统编程65 进程,线程间通信3 - 信号量数组
下一篇:Linux系统编程63 进程,线程间通信1 - 管道

发表评论

最新留言

关注你微信了!
[***.104.42.241]2025年03月26日 19时22分26秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章