【发布时间】:2011-11-16 09:11:01
【问题描述】:
我正在为 Linux 编写一个 Unix 域套接字服务器。
我很快发现 Unix 域套接字的一个特点是,在创建侦听 Unix 套接字时会创建匹配的文件系统条目,而关闭套接字并不会删除它。此外,在手动删除文件系统条目之前,不可能再次将套接字bind() 指向同一路径:如果给出的路径已经存在于文件系统中,bind() 将失败并返回 EADDRINUSE。
因此,套接字的文件系统条目需要在服务器关闭时为unlink()'ed,以避免在服务器重新启动时获得EADDRINUSE。但是,这并不总是可以完成(即:服务器崩溃)。我发现的大多数常见问题解答、论坛帖子、问答网站仅建议在调用bind() 之前向unlink() 套接字提供解决方法。但是,在这种情况下,最好在unlink()'ing 之前知道进程是否绑定到此套接字。
确实,unlink()'ing 一个 Unix 套接字,而一个进程仍然绑定到它,然后重新创建侦听套接字不会引发任何错误。然而,结果是旧的服务器进程仍在运行但无法访问:旧的侦听套接字被新的“屏蔽”。必须避免这种行为。
理想情况下,使用 Unix 域套接字,套接字 API 应该具有与绑定 TCP 或 UDP 套接字时相同的“互斥”行为:“我想将套接字 S 绑定到地址 A;如果一个进程已经绑定到这个地址了,只是抱怨!“不幸的是,事实并非如此......
有没有办法强制执行这种“互斥”行为?或者,给定一个文件系统路径,有没有办法知道,通过套接字 API,系统上的任何进程是否有一个绑定到该路径的 Unix 域套接字?我应该使用套接字 API 外部的同步原语 (flock(), ...) 吗?还是我错过了什么?
感谢您的建议。
注意:Linux 的抽象命名空间 Unix 套接字似乎解决了这个问题,因为unlink() 没有文件系统条目。但是,我正在编写的服务器旨在通用:它必须对两种类型的 Unix 域套接字都具有鲁棒性,因为我不负责选择监听地址。
【问题讨论】:
标签: sockets unix-socket