目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列, 系统V消息队列目前被大量使用。考虑到程序的可移植性,新开发的应用程序应尽量使用POSIX消息队列。

消息队列是内核创建的一个数据结构,是有标识的!
对于有读写权限的进程来说哦,所以可以通过对共享的消息进程的读写实现不同进程之间的通信!
关于消息队列的数据结构:

#include

struct msqid_ds //!> msg queue id dscription ( 消息队列状态描述符 )
{
struct ipc_perm msg_perm; //!> 读写perms
struct msg * msg_first; //!> 队列中的第一个msg,对于内存的存储而言的,对用户使用没有意义
struct msg * msg_last; //!> 队列中的最后一个msg ,对于内存的存储而言的,对用户使用没有意义
msglen_t msg_cbytes; //!> 当前的队列中的bytes
msgunum_t msg_qnum; //!> 当前的队列中的message
msglen_t msg_qbytes; //!> 队列中最大允许的bytes
pid_t msg_lspid; //!> 最后一个发送msg的pid
pid_t msg_lrpid; //!> 最后一个接收msg的pid
time_t msg_stime; //!> 最后一个msg发送时间
time_t msg_rtime; //!> 最后一个msg收到时间
time_t msg_ctime; //!> 最后一个msg控制时间( time of last magctl() ) 
};

消息队列的创建:函数---> msgget():可以创建或者访问一个已经存在的queue

#include
#include
#include

int msgget( key_t key, int flag ); //!> 返回值就是操作句柄
//!> key 可以是ftok()函数的返回值或者IPC_PRIVATE
//!> flag也是读写权限(一般是:IPC_CREAT或者IPC_CREAT | IPC_EXCL)

注意创建的一个队列后的msqid_ds的初始化参数是:
msg_perm的uid和cuid是当前进程的有效用户id;gid和cgid为当前进程的有效组id
msg_ctime是当前时间
msg_qbytes:为系统限制值
其余的值都是0

关于队列的操作:
>>>>>
int msgsnd( int msqid, const void * ptr, size_t mbytes, int flag );
//!> 参数:msqid:msgget()的返回值;ptr:是一个结构体的指针struct msgbuf { long mtype; char mtext[1] };
//!> flag:可以指定为:IPC_NOWAIT,。。。

>>>>> 
int msgrcv( int msqid, void * ptr, size_t nbytes, long type, int flag );
//!> 参数:ptr;接收到的消息的储存的位置
//!> type:希望从队列获取什么样内容的消息 =0:返回第一个消息;>0 : 返回类型为type的第一个消息;<0: 返回类型值小于或等于type参数的绝对值的消息中类型值中最小的第一个消息

>>>>>
int msgctl( int msqid, int cmd, struct msqid_ds * buff );
可以完成的操作:
IPC_RMID:
删除指定队列的所有数据,只能由两种进程执行,第一个:
用户有效ID为 msg_perm.cuid或者msg_perm.uid
第二个:超级用户权限进程 
IPC_SET:
按照buff值设置msg_perm.uid, msg_perm.gid, msg_perm.mode,
msg_qbytes四个字段,执行进程同上面
IPC_STAT:
取队列中msqid_ds结构值放到buff中

二.
ftok()函数简介:
系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
ftok原型如下:
key_t ftok( char * name, int id )
fname就时你指定的文件名,id是子序号。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。

查询文件索引节点号的方法是: ls -i
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。
如果要确保key_t值不变,要目确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t值。

同一段程序,用于保证两个不同用户下的两组相同程序获得互不干扰的IPC键值。
由于etc/config.ini(假定)为应用系统的关键配置文件,因此不存在被轻易删除的问题——即使被删,也会很快被发现并重建(此时应用系统也将被重起)。
ftok()的设计目的也在于此.

三.

#include
#include 
#include
#include
#include
#include
#include
#include

#define MSG_FILE "server.c" //!> 仅仅是创建的path而已
#define BUFFER 255
#define PERM S_IRUSR | S_IWUSR

typedef struct dataType
{
long mID;
char buffer[BUFFER + 1];
}dataType;

struct msgtype
{
long mtype;
dataType mdata;
};

int main()
{
struct msgtype msg;
key_t key; //!> 每个queue都有一个自己的KEY作为标志
int msgid; //!>

if( ( key = ftok( MSG_FILE, 'a' ) ) == -1 ) //!> when fail
{ //!> 注意'a'相当于是一个标志码而已 
fprintf( stderr, "Create Key error...: %s \n", strerror( errno ) );
exit( EXIT_FAILURE );
}

if( ( msgid = msgget( key, PERM | IPC_CREAT | IPC_EXCL ) ) == -1 )//!> 创建 msg queue
{
fprintf( stderr, "Create Msg error...: %s \n", strerror( errno ) );
exit( EXIT_FAILURE );
}

printf("\nMsg id = %d \n", msgid);

//!> 注意此处的flag都是简单处理为0 
while( 1 ) //!> 接收
{
msgrcv( msgid, &msg, sizeof( struct msgtype ), 1, 0 ); 
//!> 我们可以知道type=1,所以可以知道在client中的msg标志就是1
//!> ( 必须的,我们等一下可以使用进程ID的处理 )
fprintf( stderr, "Server receive: %s \n", msg.mdata.buffer ); //!>
msg.mtype = msg.mdata.mID;
//!> 注意此处的ID必须要换成data中客户端进程的ID( 不然客户端无法识别!!!!!!! )
sprintf( msg.mdata.buffer, " %d 客户端接收的回馈!", (int)msg.mtype ); 
//!> 注意server的回馈msg已经改变
msgsnd( msgid, &msg, sizeof( struct msgtype ), 0 ); //!> 回发送给client
}

exit( 0 ); 
}

#include
#include
#include
#include
#include
#include
#include
#include
#include

#define MSG_FILE "server.c"
#define BUFFER 255
#define PERM S_IRUSR | S_IWUSR

typedef struct dataType
{
long mID;
char buffer[BUFFER + 1];
}dataType;

struct msgtype
{
long mtype;
dataType mdata;
};

int main( int argc, char ** argv ) 
{
struct msgtype msg;
key_t key;
int msgid;

if( argc != 2 ) //!> 需要输入一个字符串作为参数
{
fprintf( stderr, "Usage: %s string .\n", argv[0] );
exit( EXIT_FAILURE );
}

if( ( key = ftok( MSG_FILE, 'a' ) ) == -1 ) //!> 获得这个Key
{
fprintf( stderr, "Create Key error...: %s \n", strerror( errno ) );
exit( EXIT_FAILURE );
}

if( ( msgid = msgget( key, PERM ) ) == -1 ) //!> 获得queue的ID 
{
fprintf( stderr, "Create Msg error...:%s \n", strerror( errno ) );
exit( EXIT_FAILURE );
}

msg.mtype = 1; //!> 注意此处的type需要与server中匹配 
msg.mdata.mID = getpid(); //!> my ID
strncpy( msg.mdata.buffer, argv[1], BUFFER ); //!> 获得命令行参数而已

msgsnd( msgid, &msg, sizeof( struct msgtype ), 0 ); //!> 发送给server
memset( &msg, '\0', sizeof( struct msgtype ) ); 
msgrcv( msgid, &msg, sizeof( struct msgtype ), getpid(), 0 ); 
//!> 获得server的反馈( 注意type是自己的ID,所以就是server的发送msg中带的 )
fprintf( stderr, "Client receive: %s \n", msg.mdata.buffer ); //!> 注意只接受自己ID的msg!!!

exit( EXIT_SUCCESS );
}

2.运行
./s & //!> server 后台
./c ILOVEYOU //!> 参数是字符串

if是多客户操作:for i in 1 2 3 4 5; do ./c sss & done //!> 注意 sss 是参数而已

3.注意:
<1>:
client对于server的发送的标志是一样的才是可以的!
因为server不可以识别多个未知的client,但是对于server的反馈而言可以根据client的ID
也就是client的接受可以根据自己的进程ID来进行不同的接受( 在网络环境下可以根据Socket套接字接受 )

<2>:
注意对于msg queue 而言:必须有一个这样的数据结构:
struct msgtype
{
long mtype;
dataType mdata; //!> 注意此处的不一定只是char*,可以是自己定义的
}; //!> 但是整体的格式必须的,主要是long这个标志是必需的!!!

typedef struct dataType
{
long mID;
char buffer[BUFFER + 1];
}dataType;

注意:对于cs模式而言,server和client必须是打开同一个queue才是OK的,所以需要有相同的操作就是:
if( ( key = ftok( MSG_FILE, 'a' ) ) == -1 ) //!> 获得相同的Key
...
获得了相同的KEY后,对于msgget的操作(也就是打开文件,自己随便...)

Linux 进程通信(System V)消息队列相关推荐

  1. linux进程间通信:system V消息队列

    文章目录 基本介绍 编程接口 代码实例 消息队列的发送和接收 消息队列中的消息对象的属性控制 基本介绍 支持不同进程之间以消息(messages)的形式进行数据交换,消息能够拥有自己的标识,且内核使用 ...

  2. Linux进程间通信二 System V 消息队列简介与示例

    1. SystemV消息队列简介 消息队列,顾名思义即是存放消息的队列,内核为每个SystemV 维护了一个msg_queue的结构体,里面记录了每个消息队列的信息. struct msg_queue ...

  3. linux进程通信system v,【linux高级程序设计】(第十一章)System V进程间通信 4

    共享内存 共享内存主要用于实现进程间大量数据传输. 共享内存的数据结构定义: 系统对共享内存的限制: 共享内存与管道的对比: 可以看到,共享内存的优势: 1.共享内存只需复制2次,而管道需要4次 2. ...

  4. Linux进程通信之System V消息队列

    System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...

  5. 细说linux IPC(十):system V 消息队列

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类 ...

  6. Linux网络编程之System V消息队列

    System V消息队列函数: #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int ...

  7. 【Linux】system V 消息队列 | system V 信号量(简单赘述)

    文章目录 1 . system V 消息队列(了解) 接口 查看消息队列 2.system V 信号量 (了解) 1.进程互斥等概念的理解 2.认识信号量 3. 接口 这两部分主要是了解即可,为后面学 ...

  8. System V 消息队列概念以及相关函数(msgget、msgsnd、msgrcv、msgctl)介绍

    System V 消息队列 消息队列是半双工的通信方式 1.1 创建一个消息队列 消息队列的特点:消息只能一条的读取,不能多读取,也不能少读取,每条消息有一个类型,可以按照消息的类型读取 创建或者打开 ...

  9. system V消息队列的使用

    最近在学习网络,主要是<UNIX网络编程>这本书,现在给大家分享以下我在学习消息队列这一部分的心得和体会,如果有不足之处希望大家批评指正. 大家知道linux中支持Posix消息队列和Sy ...

  10. System V 消息队列

    一.System V 消息队列 有一个队列,队列存放各种消息.每个进程可以把数据封存在消息中,再放入队列.每个进程都可以拿到消息队列,再从中取出/放入消息. 消息队列也有管道一样的不足,就是每个消息的 ...

最新文章

  1. 因果关系是通向强AI的阶梯or作用被夸大?
  2. 基于OpenCV的视频处理管道
  3. oracle和dba,oracle db、dba和rdba
  4. oracle 加查询锁,oracle 锁查询 select加锁方法
  5. 西建大历年电子与通信工程复试真题_历年复试试题回忆
  6. struts2+extjs文件上传完整实现(攻克了上传中的各种问题)
  7. Java基础知识盘点(二)- 集合篇
  8. java AST 表达式_java AST JCTree简要分析
  9. 5.Java 面试题整理(JDBC ,JDO 方面)
  10. 启动efi_efi启动模式对比bios启动模式有哪些优势【详细介绍】
  11. c语言程序基本设计,C语言程序的设计基本6.ppt
  12. C#:识别一个dll文件是Debug模式还是Release模式编译的
  13. unity怎么根据坐标绘制线_怎么根据阴线和阳线判断股票将稳步上涨或者下跌不止,K线组合...
  14. CodeforcesRound#498 (Div.3)E题Military Problem
  15. 谷歌地球替代软件、谷歌街景、谷歌三维城市模型查看全方案
  16. linux 查找文件及根据条件搜索文件内容
  17. iPad——添加学校邮箱到邮件解决方案
  18. php中如何插入图片,php如何添加图片
  19. 阿里云服务器AMD EPYC Milan 7T83处理器CPU性能详解
  20. 广东省汕头市谷歌卫星地图下载

热门文章

  1. Excel表格中身份证号码显示不全如何解决
  2. Facebook登陆问题和在Android 11 上的问题
  3. 无力吐槽,大乱炖吧 乱七芭蕉知识点 js基础
  4. 深度学习经历过程(caffe学习过程)
  5. python怎么交换xy轴_在python中,将x轴交换为y轴
  6. 路由入口与vue布局入口
  7. Basic Operators (基本运算符)
  8. 台式计算机网络共享,笔记本(通过网线)共享给台式机上网
  9. 华为云OBS数据桶使用
  10. 华为云教程(虚拟私有云VPC)