前面我们已经学习过了 sockaddr_un 结构,它有一个成员 sun_path,通常它保存的是一个以'\0'为结尾的绝对路径。一旦绑定了一个绝对路径,就会生成一个文件。这种 unix 域套接字地址我们称为普通 unix 域套接字地址。
还有一种 unix 域套接字地址,它的特征是 sun_path[0] 是 null,即 sun_path[0] == '\0'. 这种 unix 域套接字地址称为抽象 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 这个结果。
在 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 域套接字地址程序路径:
git clone https://git.oschina.net/ivan_allen/unp.git如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本节程序所使用的程序路径是 unp/program/unixdomainprotocols/echo_stream.
从图 3 中可以看到,Path 一栏显示的路径是 @dog,而不是 dog. 图 1 中显示的运行结果也很正常。