sendto()是否会自动为Unix域数据报套接字绑定临时路径?
sendto()行为与ss输出字段疑问 - 对于UDP套接字,
sendto()调用会尝试绑定一个临时端口。对于数据报类型的Unix域套接字,由于其不存在端口概念,仅使用路径作为地址,那么调用sendto()时是否会自动生成一个随机路径(需要文件系统中存在对应的真实文件作为支撑),或是生成随机抽象路径(例如@blah格式)并完成绑定? - 实际观测到多组处于ESTAB状态的Unix域数据报套接字对,其中部分端点的地址显示为
*(猜测对应空字符串),想了解这类端点是如何被标识的。 - 相关观测命令输出如下:
# ss -xp | grep dev-log u_dgr ESTAB 0 0 /run/systemd/journal/dev-log 15236 * 0 users:(("systemd-journal",pid=254,fd=3),("systemd",pid=1,fd=36)) # ss -xp | grep 15236 u_dgr ESTAB 0 0 /run/systemd/journal/dev-log 15236 * 0 users:(("systemd-journal",pid=254,fd=3),("systemd",pid=1,fd=36)) u_dgr ESTAB 0 0 * 19250 * 15236 users:(("dbus-daemon",pid=369,fd=14)) u_dgr ESTAB 0 0 * 21686 * 15236 users:(("dbus-daemon",pid=701,fd=10))
- 附加疑问:在Unix域套接字场景中,
ss输出里原本对应端口号位置的数字代表什么含义?
解答
sendto()的自动绑定行为
未显式绑定地址的Unix域数据报套接字调用sendto()时,既不会生成需要文件系统实体支撑的随机路径,也不会生成用户可识别的@xxx格式随机抽象路径,内核会自动为其分配一个仅内核态维护的内部标识完成绑定。
- 文件系统路径类型的Unix套接字执行绑定操作时,一定会在指定路径创建实体socket文件,内核不会擅自往文件系统写入随机文件,否则会产生无意义的磁盘垃圾、带来权限风险,不符合Unix套接字的设计逻辑。
- 你提到的
@blah格式抽象命名空间地址,是用户态程序显式指定才会生成的(构造sockaddr_un结构时将sun_path首字节设为\0,后续字节填入自定义名称),内核自动绑定不会生成这类可被用户直接识别的命名地址。
内核自动绑定的核心目的只是给套接字分配一个全局唯一的内部标识,满足数据报收发时的源地址标记、对端回包需求即可,不需要对外暴露可被其他程序主动搜索、连接的名称。
地址显示为*的端点含义
这类端点就是内核自动完成绑定、没有分配用户可见名称的Unix域套接字。
因为这类套接字没有绑定任何可打印的地址(既无文件系统路径,也无用户自定义的抽象命名空间名称),ss没有可输出的地址字符串,就用*作为占位符。观测结果里dbus-daemon持有的套接字就是典型场景:dbus-daemon没有提前为日志发送套接字绑定地址,直接调用sendto()向/run/systemd/journal/dev-log发送数据,内核给它自动完成了内部标识绑定,所以本地地址列显示为*。
ss输出中类端口数字的含义
这两个数字和TCP/UDP的端口没有任何关系,是内核为每个Unix域套接字分配的全局唯一inode编号。ss输出Unix套接字信息时的列规则为:本地地址后紧跟本地套接字的inode,对端地址后紧跟对端套接字的inode。可以交叉验证给出的输出:/run/systemd/journal/dev-log对应的套接字inode是15236,后面两行dbus-daemon持有的套接字,对端inode正好都是15236,和它们连接到journald日志套接字的实际状态完全匹配。
补充说明:Unix域套接字不强制要求绑定显式地址才能通信。无用户可见名称的套接字完全可以正常收发数据,只是其他程序无法通过文件系统路径或抽象名主动连接它,只能通过fd继承、socketpair、已建立的连接拿到它的操作句柄,这类套接字非常适合“只主动发数据、不需要被其他端主动连接”的客户端场景,不会占用任何文件系统或抽象命名空间资源。
内容的提问来源于stack exchange,提问作者QnA

