1. 普通 VS 抽象
前面我们已经学习过了 sockaddr_un 结构,它有一个成员 sun_path,通常它保存的是一个以'\0'
为结尾的绝对路径。一旦绑定了一个绝对路径,就会生成一个文件。这种 unix 域套接字地址我们称为普通 unix 域套接字地址。
还有一种 unix 域套接字地址,它的特征是 sun_path[0] 是 null,即 sun_path[0] == '\0'
. 这种 unix 域套接字地址称为抽象 unix 域套接字地址。
2. 抽象 unix 域套接字地址
使用这种套接字地址,它并不会在文件系统中产生真正的套接字文件,而是由内核帮我们维护一个抽象套接字文件,它总是以 '@'
开头,比如 @dog
。所以,它的好处自然很明显,不用产生实际文件了。
既然 sun_path[0] == '\0'
,使用普通的方法就没办法得知抽象套接字文件的名字。unix 域协议规定使用套接字地址的长度来确定 sun_path.
比如套接字地址内容如下:
struct sockaddr_un addr = {
AF_LOCAL, // 长度为 2
{'\0', 'd', 'o', 'g'} // 长度为 4
}
则该 addr 的长度应该设置为 2 + 4 = 6.
在 bind 抽象 unix 域套接字地址的时候,不能再使用 sizeof(addr) 作为 bind 的最后一个参数了,而应该使用上面计算出来的 6 这个结果。
3. unix 域套接字长度计算
在 sys/un.h 有一个宏 SUN_LEN
可以计算该 addr 的长度:
#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path))
图1 sys/un.h 中的源码
不过我们不能直接在抽象的 unix 域套接字地址上使用它,因为这个宏使用到了 strlen 函数。使用的时候可以用下面的方法:
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path + 1, "dog");
addr.sun_path[0] = '@'; // 先用非空字符占个位
len = SUN_LEN(&addr); // 计算长度
addr.sun_path[0] = 0; // 设置成抽象 unix 域套接字地址
4. 实验
程序路径:
git clone https://git.oschina.net/ivan_allen/unp.git
如果你已经 clone 过这个代码了,请使用 git pull
更新一下。本节程序所使用的程序路径是 unp/program/unixdomainprotocols/echo_stream
.
4.1 实验步骤
- 启动服务器
$ ./echo -s --path dog --abstract
- 启动客户端
$ ./echo --path dog --abstract
4.2 实验结果及分析
图2 左侧是服务器,右侧是客户端
图3 netstat 输出
从图 3 中可以看到,Path 一栏显示的路径是 @dog
,而不是 dog. 图 1 中显示的运行结果也很正常。
5. 总结
- 普通 unix 域套接字地址和抽象 unix 域套接字地址
- 如何创建抽象 unix 域套接字地址