1. unix 域协议简介
不同于 ipv4 的 AF_INET,unix 域只用于本机进程间通信,它所使用的完全是另一套协议。在使用 unix 域的时候,socket 函数的第一个参数必须指定为 AF_LOCAL 或者 AF_UNIX,表示创建一个 unix 域套接字。
2. sockaddr_un {}
不同于 ipv4 的 sockaddr_in{} 结构,unix 域的套接字地址结构为 sockaddr_un{},它包含在头文件 sys/un.h 中。
图1 sockaddr_un 的定义(linux 3.10 内核)
图 1 中的定义翻译出来就是下面这样:
struct sockaddr_un { unsigned short int sun_family; char sun_path[108]; }
算下来,这个结构体一共占用 110 个字节。
不同版本的实现可能稍有不同,比如在 unp 一书中介绍的 sun_path 成员只有 104 字节。POSIX 没有明确定义 sun_path 数组的大小。
sockaddr_un 成员里没有 ip 地址与端口号的概念,它的成员 sun_path 是某个具体的文件路径,该路径必须以'\0'
作为结尾。这种方式称为普通命名。
另一种方式是抽象命名,此时需要让 sun_path[0] = 0. 这个我们后面再说,这里我们先学会普通命名。
3. 示例——构造一个 unix 域套接字地址
构造这样的套接字地址非常简单:
struct sockaddr_un addr; addr.sun_family = AF_UNIX; // 或者让它等于 AF_LOCAL,它们的值是一样的 strncpy(addr.sun_path, "/tmp/dog", sizeof(addr.sun_path) - 1);
注意:unix 域套接字关联的路径应该是一个绝对路径名,而不是相对路径(虽然在某些系统中相对路径能够正常工作,但我们不应该使用它)。POSIX 称给 unix 域套接字相对路径名将导致未定义行为。
4. 绑定 unix 域套接字
程序路径:
git clone https://git.oschina.net/ivan_allen/unp.git
如果你已经 clone 过这个代码了,请使用 git pull
更新一下。本节程序所使用的程序路径是 unp/program/unixdomainprotocols/bindaddr
.
4.1 伪代码
int main() { int sockfd, len; struct sockaddr_un addr1, addr2; // 注意第一个参数,必须是 AF_LOCAL 或者 AF_UNIX sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); // 如果文件已经存在,删除它 unlink(pathname); // 创建 unix 域套接字地址 addr1.sun_family = AF_UNIX; strncpy(addr1.sun_path, "/tmp/dog", sizeof(addr1.sun_path) - 1); // 绑定套接字地址 bind(sockfd, (struct sockaddr*)&addr1, sizeof(addr1)); // 获取本地套接字地址,保存到 addr2 中 len = sizeof(addr2); ret = getsockname(sockfd, (struct sockaddr*)&addr2, &len); printf("bound name = %s, returned len = %d\n", addr2.sun_path, len); return 0; }
4.2 程序运行结果
在 unp/program/unixdomainprotocols/bindaddr
路径下,有一个 bindaddr 程序,这是我已经写好的。按照图 2 的方式运行:
图2 运行结果
我们看到程序 bindaddr 正常绑定了路径 /tmp/dog,同时生成了一个文件 /tmp/dog,注意观察前面的权限位,以 s 开头,表示这是一个 socket 文件。
5. 总结
- 掌握创建 unix 套接字
- 掌握 unix 域套接字地址的创建
- 掌握 bind unix 套接字地址