Linux IPC中常用函数ftok()

在使用Linux的一些IPC手段中,例如共享内存、消息队列等,有一个参数key。

下面以共享内存的shmget函数为例,如下所示:

/* shmget - allocates a System V shared memory segment 
*  shmget() returns  the identifier of the System V shared memory segment associated with the value of the argument key.
*/
int shmget(key_t key, size_t size, int shmflg);

从描述看,分配的共享内存与参数key值有关。

首先,我们实现一个共享内存的demo,两个角色:reader和writer。

首先让shmreader进程跑起来,然后运行shmwriter,随便写个字符串后回车,shmreader也能立即收到消息(这里不展示demo代码了,不是这里的重点。),如下图所示。

上述的demo中,我通过ftok("./file", 'm')这样的方式来获取key值。

下面看一下ftok函数的描述——ftok() 函数使用给定路径名命名的文件的标识(必须引用现有的、可访问的文件)和 proj_id 来生成 key_t 类型的 System V IPC 密钥。

FTOK(3)                              Linux Programmer's Manual                             FTOK(3)

NAME
       ftok - convert a pathname and a project identifier to a System V IPC key

SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>

       key_t ftok(const char *pathname, int proj_id);

DESCRIPTION
       The  ftok()  function uses the identity of the file named by the given pathname (which must
       refer to an existing, accessible file) and the least significant 8 bits of  proj_id  (which
       must  be  nonzero)  to  generate  a  key_t  type  System  V  IPC key, suitable for use with
       msgget(2), semget(2), or shmget(2).

       The resulting value is the same for all pathnames that name the same file,  when  the  same
       value  of proj_id is used.  The value returned should be different when the (simultaneously
       existing) files or the project IDs differ.

RETURN VALUE
       On success, the generated key_t value is returned.  On failure -1 is returned,  with  errno
       indicating the error as for the stat(2) system call.

从代码看key生成的逻辑:

(1)id取低8位后左移24位。

(2)获取文件设备号的低8位,并将其左移16位,作为键值的中间8位。

(3)获取文件的inode号后16位,作为键值的低16位。

key_t
ftok(const char *path, int id)
{
	const unsigned int u_id = id;
	struct stat st;

	if (stat(path, &st) == -1)
		return (key_t)-1;

	return (key_t)
	    ((u_id & 0xff) << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 0xffff));
}

下面看一个实例,获取key = ftok("./file", 0):

(1)设备号传入0,也就是高24位以后都是0。

(2)运行下面命令,左边第一个数字即为设备号。

>>> ls -l file
-r-------- 1 root root 4 Jul 27 17:51 file

(3)运行下面命令,返回197920582,是文件inode,取低16位为0x0746。

>>> ls -i file 
197920582 file

最终得出key值为0x00010746,即67398。

>>> ipcs -m

------------ 共享内存段 --------------
键        shmid      拥有者  权限     字节     连接数  状态      
0x000a4b95 0          postgres   600        56         6                       
0x00000000 1212420    mi         600        7654700    2          目标       
0x00000000 1212421    mi         600        79560      2          目标       
0x51130023 6          mi         600        152        1                       
0x00000000 9          mi         600        524288     2          目标       
0x00000000 327691     mi         600        393216     2          目标       
0x00000000 12         mi         600        524288     2          目标       
0x00000000 15         mi         600        524288     2          目标       
0x00000000 18         mi         600        524288     2          目标       
0x00000000 19         mi         600        524288     2          目标       
0x00000000 20         mi         600        524288     2          目标       
0x00000000 21         mi         600        524288     2          目标       
0x00000000 491547     mi         600        16777216   2          目标       
0x00000000 458786     mi         600        524288     2          目标       
0x00010746 2326563    mi         666        68         0                       
0x00000000 40         mi         600        524288     2          目标       
0x00000000 43         mi         600        524288     2          目标       
0x00000000 44         mi         600        524288     2          目标       
0x00000000 45         mi         600        17360      2          目标       
0x6d130001 557103     mi         666        68         0                       
0x00000000 2457648    mi         600        70800      2          目标       
0x6d010614 458801     mi         666        68         0                       
0x00000000 1703986    mi         600        524288     2          目标       
0x00000000 524339     mi         600        1405256    2          目标       
0x6d010745 524340     mi         666        68         0                       
0x6d010746 557109     mi         666        68         0                       
0x00000000 2097207    mi         600        7654700    2          目标       
0x00000000 65598      mi         600        524288     2          目标

测试debug发现:

  1. id即使写0,也能获取到key值,也能用于共享内存通信;
  2. 传入的pathname,如果是一个不存在的文件,则无法获取到key值;
  3. 传入的pathname,即使进程没有权限访问(前提是文件存在),即使文件权限为000,也可以获取到key值;
  4. 传入的pathname,即使文件内容有所修改,key值也还是不会变化的;
  5. 即使shmget传入的key值不变,只要共享内存销毁后再重新创建,对应的shmid也会发生变化;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阅后即奋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值