为什么重新绑定到套接字会随机失败?



这个问题与一个关于在 Haskell 中获取自由端口的问题有关,我在 Haskell 中包含一个检索第一个可用端口的getFreePort函数。此功能适用于 Windows 系统,但当我尝试使用我的 Linux 盒子时,它会随机失败(空闲端口报告为繁忙(。

我已经修改了函数以尝试重新绑定到免费地址,但它随机失败:

getFreePort :: IO Integer
getFreePort = do
sock <- socket AF_INET Stream defaultProtocol
bind sock (SockAddrInet aNY_PORT iNADDR_ANY)
port <- socketPort sock
close sock
print "Trying to rebind to the sock"
sock <- socket AF_INET Stream defaultProtocol
bind sock (SockAddrInet port 0x0100007f)
port <- socketPort sock
close sock
return (toInteger port)

我知道其他进程获取该端口存在争用条件,但这不太可能吗?

作为一般评论,check if a resource is available and if so take it的模式通常是一种反模式。每当您这样做时,您都会冒着另一个进程在检查之后但在您自己实际获取资源之前获取资源的风险。

进行此类检查后,您获得的唯一信息是资源未在该特定时间点使用。它可能会也可能不会帮助您猜测将来的端口状态,但您拥有的信息在以后的任何时间都不会具有约束力。您不能假设因为资源在t时是空闲的,所以它在t+dt时仍然可用。即使dt很小。当你问得很快时,它可能更有可能仍然是免费的。但仅此而已——也许概率更高。

您应该尝试获取资源并适当地处理故障。确定端口真正免费的唯一方法是当您成功打开它时。然后你知道它确实是免费的。一旦你关闭它,所有的赌注都会再次关闭。

我认为您永远无法安全地检查端口在一个进程中是否可用,然后假设它在另一个进程中仍然可用。这是没有道理的。在同一个过程中甚至没有意义!

至少你必须设计一个来回的协议:

  1. 这是一个免费的端口,请尝试一下
  2. 不,现在拿走了
  3. 好的,这是另一个
  4. 不,现在拿走了
  5. 好的,这是另一个
  6. 是的,知道了,谢谢

但这一开始就很愚蠢。需要端口的进程应该只打开它。当它已经打开端口而不是之前时,它应该将端口号传达给另一方。

最新更新