目前主要有两种类型的消息队列: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. 微软(中国)CTO韦青:人工智能是拿来用的,不是拿来炒的
  2. ehlib 用法记录
  3. ssl服务器测试网站
  4. boost::intrusive::treap_set用法的测试程序
  5. 在php中调用java接口吗,php 调用 java 接口
  6. hadoop备战:hbase的分布式安装经验
  7. android动态波浪效果,android贝塞尔曲线实现波浪效果
  8. java 解析 datatabe,在JAVA实现DataTable对象(一)
  9. 记录一次众测平台邀请码获取
  10. 《数字信号处理教程》利用matlab实现常用序列
  11. dos下拷贝服务器文件命令行,win7在DOS环境下怎么使用copy命令?使用copy命令复制文件的方法...
  12. 使用百度文字识别API进行图片中文字的识别
  13. CentOS7防火墙关闭
  14. Vue.js框架学习,数据绑定
  15. 制度是绝情的,管理是无情的,执行是合情的
  16. 关于市面上含有高级辅助驾驶功能的汽车事故问题思考
  17. 机器学习D12——决策树
  18. 绿色astah简体中文版6.8
  19. Windows Api常用函数大全
  20. String.valueOf()和Integer.valueOf()方法的使用

热门文章

  1. ASP.NET Web常用控件
  2. 迅捷路由器造成计算机无法上网,迅捷(FAST)300M无线路由器设置后不能上网的解决方法...
  3. Office小技巧|Excel表格输入身份证数字就变了乱码怎么办?
  4. 斐波那契数列C语言设计步骤,斐波那契数列c语言函数
  5. 计算机无法更改开机密码,不能修改win7电脑开机密码是怎么回事
  6. web之qq邮箱登录界面
  7. 有赞订单导出的配置化实践
  8. 计算机专业我的生涯规划档案,大学生学业生涯规划登记表11.doc
  9. Arduino和LabVIEW射频校园火警系统
  10. Go:http request cancelled 服务端感知