• UNPV2 学习:System V IPC 章节学习问题记录


    环境信息

    OS:debian11
    kernel:linux kernel 5.15

    linux 环境测试时附录源代码修改

    #ifndef MSG_R
    #define SVMSG_MODE (FILE_MODE)
    #else
    #define	SVMSG_MODE	(MSG_R | MSG_W | MSG_R>>3 | MSG_R>>6)
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5

    linux 上 System V IPC 实现的一些特点

    查看 System V IPC 占用率

    可以使用 lspic 来查询 System V IPC 状态信息,示例如下:

    RESOURCE DESCRIPTION                                              LIMIT USED  USE%
    MSGMNI   Number of message queues                                 32000   10 0.03%
    MSGMAX   Max size of message (bytes)                               8192    -     -
    MSGMNB   Default max size of queue (bytes)                        16384    -     -
    ..................................................................................
    
    • 1
    • 2
    • 3
    • 4
    • 5

    缺省的限制为 32000,lspic 能够显示消息队列的使用情况,在上面的实例中,有 10 个消息队列被使用,占用率约为 0.03%。

    System V IPC 的释放

    创建 System V IPC 的进程退出时内核不会回收 ipc,除非主动调用释放函数。ipc id 泄露完了后,再次尝试创建会报如下错误:

    msgget error: No space left on device
    
    • 1

    lsipc 能够看到如下内容:

    [longyu@debian:12:36:21] svmsg $ lsipc
    RESOURCE DESCRIPTION                                              LIMIT  USED    USE%
    MSGMNI   Number of message queues                                 32000 32000 100.00%
    .....................................................................................
    
    • 1
    • 2
    • 3
    • 4

    32000 个 id 已经被分配,占用率为 100%。
    man msgget 得到如下描述信息:

    MSGMNI System-wide limit on the number of message queues.  Before Linux 3.19, the default value for this limit was calculated using  a  formula
                  based  on  available  system  memory.  Since Linux 3.19, the default value is 32,000.  On Linux, this limit can be read and modified via
                  /proc/sys/kernel/msgmni.
    
    • 1
    • 2
    • 3

    msgmni 可以动态修改,允许修改的值有限定,比 32000 小可以正常配置,比 32000 大,需要符合特定的规律才能设定。

    [longyu@debian:12:54:17] kernel $ sudo su  -c   'echo 32600 > msgmni '
    [longyu@debian:12:54:32] kernel $ cat ./msgmni 
    32600
    
    921271566
    1102226159
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    linux 内核代码中对 System V IPC id 的描述信息

     18 /*
     19  * The IPC ID contains 2 separate numbers - index and sequence number.
     20  * By default,
     21  *   bits  0-14: index (32k, 15 bits)
     22  *   bits 15-30: sequence number (64k, 16 bits)
     23  *
     24  * When IPCMNI extension mode is turned on, the composition changes:
     25  *   bits  0-23: index (16M, 24 bits)
     26  *   bits 24-30: sequence number (128, 7 bits)
     27  */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    linux 内核的 IPC ID 由 index 与 sequence number 两部分数值拼接而成。默认配置下这两部分数值关系如下:

    1. 低 0-14 位,共计 15 位为 index 的值
    2. 高 15-30 位,共计 16 位为 sequence number 的值

    当 IPCMNI 扩展模式使能时,IPC id 值的生成规则如下:

    1. 低 0-23 位,共计 24 位为 index 的值
    2. 高 24-30 位为 sequence number 的值

    Exercises 3.1:获取 ipc_perm 与 seq number 的值

    示例代码:

    int
    main(int argc, char **argv)
    {
    	int		i, msqid;
    	struct msqid_ds info;
    
    	for (i = 0; i < 20; i++) {
    		msqid = Msgget(IPC_PRIVATE, SVMSG_MODE | IPC_CREAT);
    		printf("msqid = %d\n", msqid);
    		Msgctl(msqid, IPC_STAT, &info);
    		
    		printf("ipc_perm seq number is %d\n", info.msg_perm.__seq);
    		Msgctl(msqid, IPC_RMID, NULL);
    	}
    
    	exit(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行结果如下:

    msqid = 921370624
    ipc_perm seq number is 28118
    msqid = 921370625
    ............................
    ipc_perm seq number is 28119
    msqid = 921403393
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    每 64 个 msqid seq 递增一次。数字上的关系为 seq * 512 * 64 + 1 为下一组 64 个 msgid 的起始值。

    10 进制与 2 进制对比:

    110110111010110 28118
    110110111010110000000000000001 921370625
    
    • 1
    • 2

    能够发现 28118 是 921370625 的高 15 位值。

    Exercises 3.2:msq 每次获取返回的 id 值的变化特点

    测试记录
    0~63
    32768-32831
    65536- 65599
    98304-98367

    每 64 个 id 值为一组连续空间,超过 64 后起始值按照某种规律重新生成。

    Exercises3.3:创建 fifo 与 msgq 时对 umask 的使用

    umask 的值:0022
    示例代码:

    int		i, msqid;
    
    #define TEST_FIFOPATH "/tmp/test_fifo"
    	struct msqid_ds info;
    	struct stat statbuf;
    
    	mkfifo(TEST_FIFOPATH, 0666);
    	stat(TEST_FIFOPATH, &statbuf);
    	unlink(TEST_FIFOPATH);
    	printf("fifo perm is %o\n", statbuf.st_mode);
    
    	msqid = Msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
    	Msgctl(msqid, IPC_STAT, &info);
    	Msgctl(msqid, IPC_RMID, NULL);
    	printf("msgq perm is %o\n", info.msg_perm.mode);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试结果:

    fifo perm is 10644
    msgq perm is 666
    
    • 1
    • 2

    system V ipc 消息队列创建时不会使用 umask 来去除必要的权限,fifo 在创建时会使用 umask 去掉必要的权限。

    man mkfifo 得到的信息:

    DESCRIPTION
           mkfifo()  makes a FIFO special file with name pathname.  mode specifies the FIFO's permissions.  It is modified by the process's umask
           in the usual way: the permissions of the created file are (mode & ~umask).q
    
    • 1
    • 2
    • 3

    man msgget 未搜索到任何与 umask 相关的内容与测试结果一致。

    Exercises3.4:服务端为客户端创建唯一消息队列时那种方式更适用?

    1. 使用程序名作为固定的路径名作为参数用 ftok 生成 key 来创建

    在这种方式下,编码约定、引入三方通信框架将路径名代表的消息队列通知客户端,客户端使用相同的路径名用 ftok 生成 key 获取 server 创建的消息队列。当需要创建多个消息队列时,需要指定多个路径以区分不同的实例。

    2. 使用 IPC_PRIVATE 标志让内核自行分配 id 创建

    在这种方式下,服务端与客户端之间需要依赖第三方的通信框架以将消息队列的标识符通知客户端,当有多个客户端时,使用这种方式避免了第一种方式中提供多个文件路径的行为,然而此种方式却不能简单的通过编码约定来关联同一个消息队列。

    Exercises3.5:使用 find 批量化查找文件并制作参数使用 ftok 生成 key

    示例命令:

    find / -print   | xargs -i ./svipc/ftok '{}' > output
    
    • 1

    初步观察未找到相同的 key。

  • 相关阅读:
    计算机与操作系统
    MySQL之DQL
    Python入门教程 - 基本函数(四)
    【Python】快捷调用百度ocr能力
    基于Unet的环路滤波
    matplotlib 设置手动设置图例的位置大小
    2023最新PS(photoshop)Win+Mac免费下载安装包及教程内置AI绘画-网盘下载
    基于VUE + Echarts 实现可视化数据大屏农村信息可视化
    Ubuntu安装redis和redis-php扩展
    分布式调度Zookeeper常用Shell命令【云原生】
  • 原文地址:https://blog.csdn.net/Longyu_wlz/article/details/128159410