当前位置: 首页 > news >正文

System V通信机制

IPC对象概述

IPC对象消息队列共享内存信号量
特点多对多共享数据具备阻塞的全局变量

在这里插入图片描述

设置流程

  1. 获取IPC对象key
  2. xxxget//获取对象ID值
  3. xxxctl//操作函数
  4. 相对独立的操作函数

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_CREATIPC_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 匹配所有者/创建者。

信息结构体

struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions /
size_t shm_segsz; /
Size of segment (bytes) /
time_t shm_atime; /
Last attach time /
time_t shm_dtime; /
Last detach time /
time_t shm_ctime; /
Creation time/time of last
modification via shmctl() /
pid_t shm_cpid; /
PID of creator /
pid_t shm_lpid; /
PID of last shmat(2)/shmdt(2) /
shmatt_t shm_nattch; /
No. of current attaches */

};

信号量

是一种全局变量,在编程中想要使用一种资源,必须先要知道有没有该资源存不存在;在实际编程中使用信号量来控制对应资源;

P减操作(申请资源)
V加操作(释放资源)

并且信号量是一个集合(可以理解为数组)

1.创建创建key

创建key与消息队列相同,这里就不过多赘述

2.获得信号量的ID

函数原型int semget(key_t key, int nsems, int semflg);
头文件#include <sys/sem.h>
参数说明key:信号量集的键值,通常由 ftok 生成或直接使用 IPC_PRIVATE。nsems:信号量集中信号量的数量。semflg:标志位,用于指定创建或访问权限(如 IPC_CREAT、IPC_EXCL 或权限掩码)。

3.信号量的操作

函数原型int semctl(int semid, int semnum, int cmd, …);
头文件#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>
参数semid:信号量集合的标识符,由 semget 函数创建。semnum:信号量在集合中的索引(从 0 开始)。对于某些命令(如 IPC_RMID),此参数可忽略。cmd:控制命令
返回值失败时返回 -1,并设置 errno

cmd

cmd
IPC_STAT获取信号量集合的状态信息,存入 semid_ds 结构体。
IPC_SET设置信号量集合的属性(如权限)。
IPC_RMID删除信号量集合
GETVAL获取指定信号量的当前值。
SETVAL设置指定信号量的值(需通过第四个参数传递)
GETALL获取集合中所有信号量的值
SETALL设置集合中所有信号量的值

参数传递中需要union semun的情况,并且必须要自己定义

union semun {int val;                // SETVAL操作时使用的值struct semid_ds *buf;   // IPC_STAT和IPC_SET操作时的缓冲区unsigned short *array;  // GETALL和SETALL操作时的数组struct seminfo *__buf;  // IPC_INFO操作时的内部数据结构(Linux特定)
};

示例

  1. 初始化信号量值
union semun arg;
arg.val = 1; // 设置初始值为1
semctl(semid, 0, SETVAL, arg);
  1. 获取信号量状态
struct semid_ds ds;
union semun arg;
arg.buf = &ds;
semctl(semid, 0, IPC_STAT, arg);
  1. 批量初始化复制
unsigned short values[3] = {1, 2, 3};
union semun arg;
arg.array = values;
semctl(semid, 0, SETALL, arg);

4.P/V操作

函数原型int semop(int semid, struct sembuf *sops, size_t nsops);
头文件#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>
参数semid:信号量集的标识符,由 semget 创建。sops:指向 sembuf 结构体数组的指针,定义操作类型。nsops:sops 数组的长度(操作数量)。
返回值成功时返回 0,失败返回 -1 并设置 errno(如 EIDRM 信号量被删除、EINTR 被中断)。

其中sops是由下图所示
在这里插入图片描述

struct sembuf {unsigned short sem_num; // 信号量编号(从0开始)short          sem_op;  // 操作类型:正数(V操作)、负数(P操作)、0(等待0)short          sem_flg; // 标志位,如 一般为0
};
http://www.xdnf.cn/news/1307287.html

相关文章:

  • Docker之安装部署——(1)配置国内docker镜像源
  • 【Twincat3】IO的SCAN 不可选中,SCAN中后扫描不到设备
  • 代码随想录二刷之“字符串”~GO
  • 嵌入式开发学习———Linux环境下网络编程学习(二)
  • 科普:Pygame 中,`pg.Surface` v.s. `screen`
  • 电工的基础知识以及仪器的使用
  • 浏览器面试题及详细答案 88道(45-55)
  • 吉他和弦学习:从音程基石到流畅弹奏
  • 机器学习——PCA(主成分分析)降维
  • MySQL快速恢复数据的N种方案完全教程
  • JavaWeb开发_Day12
  • 云原生俱乐部-杂谈2
  • UI-TARS-Desktop 深度解析:下一代智能自动化桌面平台
  • 数据处理与统计分析 —— numpy入门
  • 《Attention-driven GUI Grounding》论文精读笔记
  • 【Spring Cloud 微服务】1.Hystrix断路器
  • 【LeetCode 热题 100】55. 跳跃游戏
  • @mcp.tool如何从函数定义映射到llm系统输入
  • 如何回答研究过MQ的源码吗
  • 【121页PPT】智慧方案智慧综合体智能化设计方案(附下载方式)
  • [优选算法专题二滑动窗口——长度最小的子数组]
  • Effective C++ 条款42:了解 typename 的双重含义
  • AutoSar AP平台中EM,CM,SM,PHM,LT等AP基础软件都有宿主进程吗
  • Lecture 10: Concurrency 3
  • linux-数据链路层
  • C语言笔记6:C高级 part1
  • 【160页PPT】机械行业数字化生产供应链产品解决方案(附下载方式)
  • 深入理解Transformer:从训练机制到长文本处理的核心问题
  • GoLand深度解析:智能开发利器与cpolar内网穿透的协同革命
  • Linux系统编程—Linux基础指令