首页 文章

如何知道任何进程是否绑定到Unix域套接字?

提问于
浏览
33

我正在为Linux编写一个Unix域套接字服务器 .

我很快发现Unix域套接字的一个特点就是,在创建一个侦听Unix套接字创建匹配的文件系统条目时,关闭套接字不能再次使用同一路径的套接字: bind() 如果路径失败 EADDRINUSE 它已经存在于文件系统中 .

因此,套接字的文件系统条目需要在服务器关闭时进行 unlink() ,以避免在服务器重启时获得 EADDRINUSE . 但是,这不能总是这样做(即:服务器崩溃) . 我发现的大多数常见问题解答,论坛帖子,问答网站只是在调用 bind() 之前建议,作为解决方法 . 但是,在这种情况下,需要知道进程是否在它之前绑定到此套接字 .

的确, unlink() 'ing a Unix socket while a process is still bound to it and then re-creating the listening socket doesn' t引发任何错误 . 但是,结果是,旧的服务器进程仍在运行但无法访问:新的侦听套接字是"masked" . 必须避免这种行为 .

理想情况下,使用Unix域套接字时,套接字API应该暴露出绑定TCP或UDP套接字时暴露的相同行为:“我想将套接字S绑定到地址A;如果进程已经绑定到此地址,则只需要抱怨!”不幸的是,这种情况并非如此...

有没有办法强制执行此"mutual exclusion"行为?或者,给定一个文件系统路径,有没有办法通过套接字API知道系统上的任何进程是否有绑定到此路径的Unix域套接字?我应该使用套接字API外部的同步原语( flock() ,...)?或者我错过了什么?

谢谢你的建议 .

注意:Linux的抽象命名空间Unix套接字似乎解决了这个问题,因为 unlink() 没有文件系统条目 . 但是,我正在编写的服务器旨在通用:它必须对两种类型的Unix域套接字都是健壮的,因为我不负责选择侦听地址 .

2 回答

  • 9

    我知道我参加聚会已经很晚了,很久以前就回答了这个问题,但我刚刚遇到了这个搜索其他内容的问题 .

    当您从 bind() 遇到 EADDRINUSE 返回时,您可以输入连接到套接字的错误检查例程 . 如果连接成功,则有一个至少足够活跃的运行进程来完成 accept() . 这让我觉得这是实现您想要实现的目标的最简单,最便携的方式 . 它的缺点在于,首先创建UDS的服务器实际上可能仍在运行,但是某种方式无法执行 accept() ,所以这个解决方案肯定不是万无一失的,但它是朝着正确方向迈出的一步我认为 .

    如果 connect() 失败,则继续并终止 unlink() 并再次尝试 bind() .

  • 21

    我认为除了你已经考虑过的事情之外还有很多工作要做 . 你似乎已经很好地研究了它 .

    有一些方法可以确定套接字是否绑定到unix套接字(显然是lsof和netstat这样做)但是它们很复杂并且系统依赖性足以让我怀疑它们是否值得努力处理你引发的问题 .

    您实际上提出了两个问题 - 处理与其他应用程序的名称冲突以及处理您自己的应用程序的先前实例 .

    根据定义,您的pgm的多个实例不应该尝试绑定到同一路径,这可能意味着您一次只需要一个实例运行 . 如果是这种情况,您可以使用标准的pid文件锁定技术,因此两个实例不会同时运行 . 如果无法获得锁定,则不应取消现有套接字的链接,甚至不应运行 . 这也会处理服务器崩溃情况 . 如果您可以获得锁定,那么您知道可以在绑定之前取消链接现有套接字路径 .

    没有太多可以做AFAIK来控制其他创建碰撞的程序 . 文件权限并不完美,但如果您可以使用该选项,则可以将应用程序放在自己的用户/组中 . 如果存在现有的套接字路径并且您不拥有它,则不要取消链接并发出错误消息并让用户或系统管理员对其进行排序 . 使用配置文件使其易于更改 - 并且可供客户端使用 - 可能会起作用 . 除此之外,您几乎必须进行某种发现服务,除非这是一个非常关键的应用程序,否

    总的来说,你可以采取一些安慰,这实际上并不经常发生 .

相关问题