System V IPC进程间通信——消息队列

本文介绍了System V IPC中的消息队列,作为进程间通信的一种方式,讲解了如何创建、获取消息队列,以及发送、接收和控制消息的函数msgget、msgsnd、msgrcv和msgctl的使用。文章还提供了客户端和服务端的代码示例,展示了实际操作过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

System V IPC

IPC 是进程间通信(Interprocess Communication)的缩写,通常指允许用户态进程执行下列操作的一组机制

  • 通过信号量与其他进程进行同步
  • 向其他进程发送消息或者从其他进程接收消息
  • 和其他进程共享一段内存

System V IPC 最初是在一个名为“Columbus Unix” 变体中引入的,现在大部分Unix系统中都可以找到。

IPC 资源

IPC资源包括信号量、消息队列、共享内存,IPC数据结构是在请求IPC时动态创建的,每个IPC资源都是持久的,除非被进程释放,否则永远驻留在内存中,直到系统关闭。根据IPC新资源时信号量、消息队列、还是共享内存区,分别调用semget(),msgget(),shmget()函数创建IPC资源。本章详细讲一下消息队列。

消息队列

进程间通过IPC消息队列通信,进程产生的每条消息都被发送到一个IPC消息队列中,这个消息一直存放在队列中,直到另外一个进程将其读走,故消息只适用于两个进程间通信。消息是由固定大小的首部,该首部是一个long int 型,用来存放消息类型和可变长度的正文组成。

创建、获取一个消息队列-msgget()

int msgget(key_t key, int msgflg)

key : 键值,每一个消息队列都有一个键值,一般有函数ftok生成,也可以自定定义,是一个32位整形
msgflg:消息队列标识符,同时设定该队列的权限,
msgflg的值为IPC_CREAT:如果不存在key值的消息队列,且权限不为0,则创建消息队列,并返回一个消息队列ID。如果存在,则直接返回消息队列ID。
msgflg的值为 IPC_CREAT | IPC_EXCL:如果不存在key值的消息队列,且权限不为0,则创建消息队列,并返回一个消息队列ID。如果存在,则产生错误。

发送消息函数-msgsnd()

int msgsnd(int msgid,const void *ptr,size_t nbytes,int flag);

msgid:通过函数msgget 返回的队列标识符。
ptr:发送消息结构,包括一个固定大小的首部和可变长度的正文
nbytes:正文长度
flag:值可以为0或者IPC_NOWAIT。为0时,当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列或者消息队列被删除。为IPC_NOWAIT时,当消息队列满了,msgsnd函数将不会等待,会立即出错返回EAGAIN

接收消息函数-msgrcv()

ssize_t msgrcv(int msgid,void *ptr,size_t nbytes,long type,int flag);

msgid:通过函数msgget 返回的队列标识符。
ptr:接收消息结构,包括一个固定大小的首部和可变长度的正文
nbytes:正文长度
type: 该值是发送消息结构的首部消息类型

	type ==0 返回队列中的第一个消息
    type > 0 返回队列中消息类型为type的第一个消息
    type < 0 返回队列中消息类型值小于等于type绝对值的消息,如果这种消息有若干个,则取类型值最小的消息

flag:可以为0、IPC_NOWAIT、IPC_EXCEPT

    为0时,阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
    为IPC_NOWAIT时,如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG
    为IPC_EXCEPT时,与msgtype配合使用返回队列中第一个类型不为msgtype的消息

消息控制函数-msgctl()

int msgctl(int msgid, int cmd, struct msqid_ds *buf);

msgid:通过函数msgget 返回的队列标识符。
cmd有三个,常用删除消息队列的为IPC_RMID;IPC_STAT:取此队列的msqid_ds结构,并将它存放在buf指向的结构中;IPC_SET:改变消息队列的状态,把buf所指的msqid_ds结构中的uid、gid、mode复制到消息队列的msqid_ds结构内。可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes

接下来是客户端和服务端的代码例子

server.c
<

key_t key = ftok("/home", 24);
int msgid = msgget(key,O_RDONLY);
if(msgid<0)
{   
    LOG_INFO("recv msgget error!");
    exit(-1);
}
memset(&rcv, 0, sizeof(rcv));
msgrcv(msgid,&rcv,sizeof(rcv)-sizeof(rcv.msg_type),8,IPC_NOWAIT);
msgctl(msgid,IPC_RMID,NULL);

client.c
<

key = ftok("/home", 24);
msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
if(msgid<0)
{	
	LOG_INFO("msgget error!\n");
	goto out;
}	
msg.msg_type = 8;
strncpy(msg.modul_name,"hello", 5);
msgsnd(msgid,&msg,sizeof(msg)-sizeof(msg.msg_type),0);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值