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

Sim*_*nge 34 sockets unix-socket

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

我很快发现Unix域套接字的一个特点就是,在创建一个侦听Unix套接字创建匹配的文件系统条目时,关闭套接字不会删除它.此外,在手动删除文件系统条目之前,不可能再次bind()将套接字转到同一路径:如果文件系统中已存在已给出的路径,则bind()失败EADDRINUSE.

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

实际上,unlink()当进程仍然绑定到它然后重新创建侦听套接字时,使用Unix套接字不会引发任何错误.但是,结果是,旧的服务器进程仍在运行但无法访问:旧的侦听套接字被新的监听套接字"屏蔽".必须避免这种行为.

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

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

谢谢你的建议.

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

Kea*_*ean 21

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

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

如果connect()失败则继续unlink()进行端点并bind()再次尝试.


Duc*_*uck 9

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

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

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

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

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

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