System V IPC 消息队列

/usr/include/linux/ipc.h

#define IPC_PRIVATE ((__kernel_key_t) 0)

struct ipc_perm
{
  __kernel_key_t  key;  /* Key supplied to xxxget(2) */
  __kernel_uid_t  uid;  /* Effective UID of owner */
  __kernel_gid_t  gid;  /* Effective GID of owner */
  __kernel_uid_t  cuid; /* Effective UID of creator */
  __kernel_gid_t  cgid; /* Effective GID of creator */
  __kernel_mode_t mode; /* Permissions */
  unsigned short  seq;  /* Sequence number */
};

System V IPC 用到的一个公共结构体,其中,ipc_perm.key 被称之为 ipckey,
进程间通信本质上其实就是在内核中申请一定的资源,而 ipckey 就描述着内核中唯一一个消息队列(一块共享内存/一个信号量集)这样的资源,
毕竟一个操作系统可以创建出很多个消息队列
/usr/include/linux/msg.h

struct msqid_ds 
{
  struct ipc_perm msg_perm;
  struct msg        *msg_first;   /* first message on queue,unused  */
  struct msg        *msg_last;    /* last message in queue,unused */
  __kernel_time_t    msg_stime;   /* last msgsnd time */
  __kernel_time_t    msg_rtime;   /* last msgrcv time */
  __kernel_time_t    msg_ctime;   /* last change time */
  unsigned long      msg_lcbytes; /* Reuse junk fields for 32 bit */
  unsigned long      msg_lqbytes; /* ditto */
  unsigned short     msg_cbytes;  /* current number of bytes on queue */
  unsigned short     msg_qnum;    /* number of messages in queue */
  unsigned short     msg_qbytes;  /* max number of bytes on queue */
  __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
  __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};

描述消息队列的结构体
功能:专门用于生成 ipckey
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
参数:
	pathname:存在且可访问的目录/文件
	proj_id:虽说是 int 类型,但只有低 8 位有效
返回值:
	成功返回 key_t(类似 pid_t) 值
	失败返回 -1,并设置错误码
注意:传入的参数相同,生成的 key_t 值相同

ftok()传参需知

功能:创建/打开一个消息队列
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
参数:
	key:ftok() 返回值
	msgflg:
		IPC_CREAT:如果消息队列不存在就创建,如果存在就打开
			用于打开一个消息队列
		IPC_CREATE | IPC_EXCL | 0666:如果消息队列不存在就创建,如果存在就返回 -1
			用于创建一个消息队列
返回值:
	成功返回非 0 值的消息队列句柄
	失败返回 -1,并设置错误码

/* ################################################################ */

功能:消息队列的控制函数
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
	msqid:msgget() 返回值
	cmd:
		IPC_STAT:将与 msqid 相关联的 msqid_ds 数据结构的每个成员值放入 buf 指向的结构中
		IPC_SET:在进程有足够权限的前提下,可以修改与 msqid 相关联的 msqid_ds 数据结构的以下成员值 
			msg_perm.uid
			msg_perm.gid
			msg_perm.mode
			msg_qbytes:消息队列的总字节数
		IPC_RMID:在进程有足够权限的前提下,删除消息队列
返回值:
	成功返回 0
	失败返回 -1,并设置错误码
	
/* ################################################################ */

功能:发送一条消息到消息队列中
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
	msqid:msgget() 返回值
		struct msgbuf 
		{
			long mtype;       /* Message type, must > 0 */
    		char mtext[1];    /* Message text, max MSGMAX */
		}
	msgp:struct msgbuf
	msgsz:sizeof(msgbuf.mtext)
	msgflg:
		& IPC_NOWAIT:队列满时不等待,返回 -1,并设置 EAGAIN 错误码
返回值:
	成功返回 0
	失败返回 -1,并设置错误码

/* ################################################################ */

功能:从消息队列中接收一条消息
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:
	msqid:msgget() 返回值
	msgp:struct msgbuf
	msgsz:sizeof(msgbuf.mtext)
	msgtyp:
		= 0:接收队列中第一条消息
		> 0:接收队列中类型等于 msgtype 的第一条消息
		< 0:接收队列中 <= msgtyp 绝对值的最低类型的第一条消息
	msgflg:
		& IPC_NOWAIT:队列没有类型等于 msgtyp 的消息时不等待,返回 -1,并设置 ENOMSG 错误码
		& MSG_NOERROR:接收到的消息长度大于 msgsz 时,将其截断成 msgsz 字节大小
		& MSG_NOERROR is 0:接收到的消息长度大于 msgsz 时,返回 -1,并设置 E2BIG 错误码
		& MSG_EXCEPT && msgtype > 0:接收类型不等于 msgtype 的第一条消息
返回值:
	成功返回实际放入缓冲区 msg_buf.mtext 的字节数
	失败返回 -1,并设置错误码

用消息队列实现简单的 Client&Server 通信

特点
1、全双工通信
2、可以发送带有类型的数据块,此处的类型指的是具体的业务场景
3、操作系统上的消息队列总数有一个上限(MSGMNI),每个消息队列的总字节数有一个上限(MSGMNB,每个消息队列中所有消息长度总和 Σsizeof(msgbuf.mtext) 最大是 16384,测试验证),每个消息的字节数有一个上限(MSGMAX)

$ ipcs -q -l

------ Messages Limits --------
max queues system wide = 32000
max size of message (bytes) = 8192
default max size of queue (bytes) = 16384

$

4、消息队列是数据结构-队列的应用,但消息队列并没有严格遵守先进先出规则,根据特点2,消息队列严格遵守基于类型的先进先出规则,举个现实生活中的例子,超声科室出来个医生说:“过来一个检查胃的”,此时即便产检的排在队列的第一位,也不是她出队,而是在检查胃中排在最前的先出
5、进程退出,如果代码中并没有销毁(msgctl(IPC_RMID))动作的话,消息队列是不会被释放的,也就是消息队列的生命周期随内核,当然也可以通过 ipcrm -q +msqid 手动删除,或者重启主机

$ ipcs -q

------ Message Queues --------
key        msqid     owner      perms      used-bytes   messages
0x00000000 0         root       660        0            0
0x00000000 1         root       660        0            0
0x00000000 2         root       660        0            0
0x01026636 16        mam        666        0            0

$ ipcrm -q 16
$ ipcs -q

------ Message Queues --------
key        msqid     owner      perms      used-bytes   messages
0x00000000 0         root       660        0            0
0x00000000 1         root       660        0            0
0x00000000 2         root       660        0            0

$
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值