System V通信机制
IPC对象概述
IPC对象 | 消息队列 | 共享内存 | 信号量 |
---|---|---|---|
特点 | 多对多 | 共享数据 | 具备阻塞的全局变量 |
设置流程
- 获取IPC对象key
- xxxget//获取对象ID值
- xxxctl//操作函数
- 相对独立的操作函数
IPC相关bash命令
ipcs [-参数]
>-a:显示所有 IPC 设施(默认选项)。
>-q:仅显示消息队列。
>-m:仅显示共享内存段。
>-s:仅显示信号量。
>-l:显示 IPC 资源的系统限制。
>-u:显示 IPC 设施的汇总信息。
>-p:显示与 IPC 设施相关的进程 ID。
>-t:显示时间信息,如上次操作时间。
>-c:显示创建者的用户和组信息。
>-b:显示 IPC 设施的权限和大小信息。ipcrm -[参数]#在bash中删除IPC对象
> -m, --shmem-id <id> remove shared memory segment by id
> -M, --shmem-key <key> remove shared memory segment by key
> -q, --queue-id <id> remove message queue by id
> -Q, --queue-key <key> remove message queue by key
> -s, --semaphore-id <id> remove semaphore by id
> -S, --semaphore-key <key> remove semaphore by key
> -a, --all[=shm|msg|sem] remove all (in the specified category)
> -v, --verbose explain what is being done
> -h, --help display this help
> -V, --version display version
消息队列
1.创建key
函数原型 | key_t ftok(const char *pathname, int proj_id); |
---|---|
头文件 | #include <sys/ipc.h> |
参数 | pathname:指向一个已存在文件的路径字符串,key:一个 8 位的项目标识符(范围 0-255) |
返回值 | 成功返回key_t类型,失败返回*-1* |
2.创建对象
函数原型 | int msgget(key_t key, int msgflg); |
---|---|
头文件 | #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
参数 | key:由 ftok msgflg:标志位,用于指定队列的权限和创建行为 |
返回值 | 成功时返回消息队列的标识符(非负整数)。失败时返回 -1 |
msgflg | |
---|---|
IPC_CREAT | IPC_CREAT:如果队列不存在,则创建。 |
IPC_EXCL | 与 IPC_CREAT 一起使用,确保队列不存在时创建,否则返回错误。 |
权限模式 | IPC_CREAT|0666:在创建时同时复制权限 |
3.进行发送
函数原型 | int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); |
---|---|
头文件 | #include <sys/msg.h> |
参数 | msqid:消息队列标识符,由 msgget 函数返回。msgp:指向消息缓冲区的指针,缓冲区需包含消息类型和消息内容。msgsz:消息正文的大小(以字节为单位),不包括消息类型字段;msgflg:控制标志,通常为 0(阻塞模式)或 IPC_NOWAIT(非阻塞模式)。 |
返回值 | 成功时返回 0,失败时返回 -1 并设置 errno。 |
msgflag | |
---|---|
IPC_NOWAIT | 非阻塞模式 |
0 | 进行阻塞 |
在创建根据手册描述需要创建一个包含正文,和类型的结构体
struct msgbuf {long mtype; // 消息类型,必须为正整数char mtext[1]; // 消息正文,实际使用时需自定义长度
};
示例
typedef struct msgbuf
{long mtype; /* message type, must be > 0 */char mtext[1024]; /* message data */
}msgbuf;int main(void)
{key_t key = ftok(".", 123);//在当前路径下创建生成一个"钥匙"int mag_id = msgget(key, IPC_CREAT | 0664);//创建一个新的消息队列msgbuf my_msbuf;my_msbuf.mtype = 100;memset(my_msbuf.mtext, 0, sizeof(my_msbuf.mtext));scanf("%s", my_msbuf.mtext);msgsnd(mag_id, &my_msbuf, strlen(my_msbuf.mtext), 0);//进行阻塞的发送信息return 0;
}
运行结果
4.进行接收
函数原型 | int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); |
---|---|
头文件 | #include <sys/msg.h> |
参数 | msqid:消息队列标识符,由 msgget 创建。msgp:通常是一个结构体,包含消息类型和消息正文。msgsz:消息正文的大小msgtyp:指定接收的消息类型;msgflg:控制行为的标志位 |
返回值 | 成功时返回实际接收的消息正文的字节数。失败时返回 -1,并设置 errno。 |
msgflag | |
---|---|
IPC_NOWAIT | 如果没有符合条件的消息,立即返回错误(不阻塞) |
MSG_NOERROR | 如果消息正文超过 msgsz,截断消息而不报错。 |
0 | 进行阻塞 |
示例
int main(void)
{key_t key = ftok(".", 123);//在当前路径下创建生成一个"钥匙"int mag_id = msgget(key, IPC_CREAT|0664);//创建一个新的消息队列msgbuf my_msbuf;my_msbuf.mtype = 200;while (1){memset(my_msbuf.mtext, 0, sizeof(my_msbuf.mtext));msgrcv(mag_id, &my_msbuf, sizeof(my_msbuf.mtext), 100, MSG_NOERROR);//进行阻塞的发送信息printf("2接收到程序:%s\n", my_msbuf.mtext);}
}
运行结果
5.操作消息队列
函数原型 | int msgctl(int msqid, int cmd, struct msqid_ds *buf); |
---|---|
头文件 | #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> |
参数 | msqid:消息队列的标识符,由 msgget 函数创建或获取。cmd:控制命令;buf:指向 struct msqid_ds 的指针,用于存储或设置消息队列的属性。 |
返回值 | 成功时返回 0。失败时返回 -1,并设置 errno 以指示错误类型。 |
属性信息结构体struct msqid_ds
struct msqid_ds {struct ipc_perm msg_perm; // 权限信息time_t msg_stime; // 最后发送消息的时间time_t msg_rtime; // 最后接收消息的时间time_t msg_ctime; // 最后修改时间unsigned long __msg_cbytes; // 当前队列中的字节数msgqnum_t msg_qnum; // 当前队列中的消息数msglen_t msg_qbytes; // 队列的最大字节数pid_t msg_lspid; // 最后发送消息的进程 PIDpid_t msg_lrpid; // 最后接收消息的进程 PID
};
常用命令
cmd | |
---|---|
IPC_STAT | 获取消息队列的属性,存储到 buf 指向的结构体中 |
IPC_SET | 设置消息队列的属性,从 buf 指向的结构体中读取 |
IPC_RMID | 立即删除消息队列,忽略 buf 参数 |
示例
int main(void)
{key_t key = ftok(".", 123);//在当前路径下创建生成一个"钥匙"int mag_id = msgget(key, IPC_CREAT | 0664);//创建一个新的消息队列msgbuf my_msbuf;my_msbuf.mtype = 100;struct msqid_ds msginfo;msgctl(mag_id, IPC_STAT,&msginfo);printf("信息数量:%lu\n", msginfo.msg_qnum);return 0;
}
运行结果
消息队列是流操作
共享内存
1.创建创建key
创建key与消息队列相同,这里就不过多赘述
*2.创建shareMemoryID
函数原型 | int shmget(key_t key, size_t size, int shmflg); |
---|---|
头文件 | #include <sys/ipc.h> #include <sys/shm.h> |
参数 | key:共享内存段的键值,通常由 ftok 生成或直接使用 IPC_PRIVATE。size:共享内存段的大小,通常是4096的倍数。如果是获取已存在的共享内存,此参数可设为 0。shmflg:权限标志 |
返回值 | 成功时返回共享内存段的标识符(非负整数)。失败时返回 -1,并设置 errno 表示错误原因。 |
shmflg
shmflg | |
---|---|
IPC_CREAT | 创建,可以与限权相或进行设置 |
IPC_EXCL | 确保在创建新的 IPC 资源(如共享内存、消息队列或信号量)时,如果该资源已存在,则创建操作会失败。 |
3.映射内存
函数原型 | void *shmat(int shmid, const void *shmaddr, int shmflg); |
---|---|
头文件 | #include <sys/shm.h> |
参数 | shmid:共享内存标识符,由 shmget 调用返回;shmaddr:指定共享内存附加到进程地址空间的位置。通常设为 NULL,由系统自动选择地址。shmflg:附加标志,例如 SHM_RDONLY 表示只读访问。 |
返回值 | shmat 返回共享内存附加到进程地址空间的起始地址。失败时,返回 (void *)-1,并设置 errno 以指示错误原因。 |
shmflg
shmflg | |
---|---|
0 | 默认,代表共享内存可读可写。 |
SHM_RDONLY | 代表共享内存只读。 |
示例
int main(void)
{key_t key = ftok(".", 1);//在当前路径下创建生成一个"钥匙"if(key == -1){perror("ftok sailed\n");}int shm_ID = shmget(key, 4096, IPC_CREAT|0664);if (shm_ID == -1) {perror("shmget failed\n");exit(1);}int shmdt(const void *shmaddr);char * add = shmat(shm_ID, NULL, 0);sprintf(add, "1234");printf("%s", add+1);return 0;
}
执行结果
操作
函数原型 | int shmctl(int shmid, int cmd, struct shmid_ds *buf); |
---|---|
头文件 | #include <sys/ipc.h> #include <sys/shm.h> |
参数 | shmid:指定的共享内存的ID;cmd:一些命令字;buf:用来存放共享内存信息的结构体 |
返回值 | 失败返回-1 |
cmd参数说明
cmd | |
---|---|
IPC_STAT | 将共享内存的当前状态信息复制到 buf 指向的 shmid_ds 结构中。调用者需具备读权限。 |
IPC_SET | 通过 buf 修改共享内存的权限、所有者或时间戳等字段。仅超级用户或有效用户 ID 与共享内存所有者/创建者匹配的用户可执行。 |
IPC_RMID | 标记共享内存段为待销毁状态。实际销毁会在最后一个附加进程分离后发生。此操作需超级用户或有效用户 ID 匹配所有者/创建者。 |