⭕️
IPC对象
-
IPC 对象包含: 共享内存、消息队列和信号量
-
每个IPC对象有唯一的ID(IPC对象创建的时候由系统分配的一个数字,只有创建IPC对象的进程可以获得ID,别的进程不知道这个ID号)
-
IPC对象创建后一直存在,直到被显式地删除
-
每个IPC对象有一个关联的KEY(可以看成IPC对象的一个属性,通过KEY值,可以使不同的进程能够打开同一个IPC对象。创建IPC对象的进程把KEY值和IPC对象关联)
-
查看IPC对象 ipcs
- 查看共享内存对象ipcs -m
- 查看消息队列对象ipcs -q
- 查看信号量ipcs -s
-
iprm删除IPC对象
ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ] ...
-
用ftok生成键值
#include<sys/types.h> #include<sys/ipc.h> key_t ftok(const char *pathname,int proj_id); /***************************** 函数功能:系统IPC键值的格式转换函数 函数参数:const char *pathname: 文件路径名 int proj_id: 子序号,虽然是int类型,但是只使用8bits 函数返回:成功:返回生成的key 出错:-1 ******************************/
- 如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值就为0x26010002
⭕️
消息队列
-
消息队列是消息的链接表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识
-
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
-
消息队列独立于发送与接收进程,进程终止时,消息队列中的内容不会被删除
-
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按照消息的类型读取
⭕️
创建或打开一个消息队列
-
msgget函数:
#include <sys/msg.h> int msgget(key_t key, int msgflg);
-
功能:创建一个新的或打开一个已经存在的消息队列。不同的进程调用此函数,只要用相同的 key 值就能得到同一个消息队列的标识符。
-
参数:
- key: IPC对象的key 值
- msgflg: 标识函数的行为及消息队列的权限,其取值如下
- IPC_CREAT:创建消息队列。 I
- PC_EXCL: 检测消息队列是否存在。
- 位或权限位:消息队列位或权限位后可以设置消息队列的访问权限,但可执行权限未使用。
-
返回值: 成功返回消息队列的标识符 ;失败返回-1
⭕️
消息队列的读写
-
消息队列的数据格式由一个结构体定义,mtext的大小可由用户分配
struct _msg { long mtype; // 消息类型 char mtext[128]; // 消息正文 };
-
发送消息msgsnd:
#include <sys/msg.h> int msgsnd( int msqid, const void *msgp, size_t msgsz, int msgflg);
-
功能: 将新消息添加到消息队列。
-
参数:
- msqid: 消息队列的标识符。
- msgp: 待发送消息结构体的地址。
- msgsz: 消息正文的字节数。
- msgflg:函数的控制属性,其取值如下:
- 0:msgsnd()调用阻塞直到条件满足为止。
- IPC_NOWAIT: 若消息没有立即发送则调用该函数的进程会立即返回。
-
返回值:成功0;失败-1
-
-
接收消息msgrcv:
#include <sys/msg.h> ssize_t msgrcv( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg );
-
功能:从标识符为 msqid 的消息队列中接收一个消息。一旦接收消息成功,则消息在消息队列中被删除。
-
参数:
-
msqid:消息队列的标识符,代表要从哪个消息列中获取消息。
-
msgp: 存放消息结构体的地址。
-
msgsz:消息正文的字节数。
-
msgtyp:消息的类型。可以有以下几种类型:
- msgtyp = 0:返回队列中的第一个消息。
- msgtyp > 0:返回队列中消息类型为 msgtyp 的消息(常用)。
- msgtyp < 0:返回队列中消息类型值小于或等于 msgtyp 绝对值的消息,如果这种消息有若干个,则取类型值最小的消息。在获取某类型消息的时候,若队列中有多条此类型的消息,则获取最先添加的消息,即先进先出原则。
-
msgflg:函数的控制属性。其取值如下:
- 0:msgrcv() 调用阻塞直到接收消息成功为止。
- MSG_NOERROR: 若返回的消息字节数比 nbytes 字节数多,则消息就会截短到 nbytes 字节,且不通知消息发送进程。
- IPC_NOWAIT: 调用进程会立即返回。若没有收到消息则立即返回 -1。
-
-
返回值: 成功读取消息的长度; 失败:-1
-
-
控制消息队列对象msgctl:
#include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- 功能:用来对消息队列的基本属性进行控制、修改。
- 参数:
- msqid:消息队列标识符。
- cmd:执行的控制命令(在ipc.h中定义):
- IPC_RMID :删除消息队列。从系统中删除给消息队列以及仍在该队列上的所有数据,这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错,并返回EIDRM。 此命令只能由如下两种进程执行:
- 1.其有效用户ID等于msg_perm.cuid或msg_perm.guid的进程。
- 2.另一种是具有超级用户特权的进程。
- IPC_SET :设置消息队列的属性。按照buf指向的结构中的值,来设置此队列的msqid_id结构。该命令的执行特权与上一个相同。
- IPC_STAT:读取消息队列的属性。取得此队列的msqid_ds结构,并存放在buf*中。
- IPC_INFO:读取消息队列基本情况。
- IPC_RMID :删除消息队列。从系统中删除给消息队列以及仍在该队列上的所有数据,这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错,并返回EIDRM。 此命令只能由如下两种进程执行:
- buf:队列中的内容,一般为NULL
⭕️
示例代码
-
A.c:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[128]; /* message data */ }; int main() { int msqid; key_t key = ftok(".",2021); struct msgbuf wrBuf = { 888,"How are you? ^_^ "}; struct msgbuf reBuf; msqid=msgget(key, IPC_CREAT|0777); if(msqid == -1){ printf("msgget error"); exit(1); } msgsnd(msqid,&wrBuf,strlen(wrBuf.mtext),0); msgrcv(msqid,&reBuf,sizeof(reBuf.mtext),999,0); printf("mtext from B:%s\n",reBuf.mtext); msgctl(msqid,IPC_RMID,NULL); return 0; }
-
B.c
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[128]; /* message data */ }; int main() { int msqid; struct msgbuf reBuf; struct msgbuf wrBuf = {999,"666666!"}; key_t key = ftok(".",2021); msqid=msgget(key, IPC_CREAT|0777) ; if(msqid == -1){ perror("msgget error"); exit(1); } if(msgrcv(msqid,&reBuf,sizeof(reBuf.mtext),888,0) == -1){ perror("msgrcv error"); }else{ printf("mtext from A:%s\n",reBuf.mtext); } if(msgsnd(msqid,&wrBuf,strlen(wrBuf.mtext),0) == -1){ perror("msgsnd error"); } if(msgctl(msqid,IPC_RMID,NULL) == -1){ perror("msgctl error"); } return 0; }
-
显示
B进程: mtext from A:How are you? ^_^ A进程: mtext from B:666666!
⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️⭕️