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

时间:2017-08-17 17:29:35

标签: sockets haskell networking

此问题与a question about getting a free port in 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)

据我所知,有关其他流程获取该端口的竞争条件,但这不太可能吗?

1 个答案:

答案 0 :(得分:3)

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

此类检查后您获得的唯一信息是该特定时间点未使用该资源。它可能会或可能不会帮助您在将来猜测端口的状态,但您拥有的信息在以后任何时候都不会受到约束。您不能认为因为资源在t时是免费的,所以t+dt仍可免费使用。即使dt非常小。当你提出 fast 时,它可能仍然是免费的。但就是这样 - 可能是更高的概率。

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

我认为你不能安全地检查一个进程中的端口是否空闲,然后假设它在另一个进程中仍然是空闲的。那没有意义。它在同一个过程中甚至没有意义!

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

  1. 这是一个免费的端口,试试
  2. 不,现在拍了
  3. 好的,这是另一个
  4. 不,现在拍了
  5. 好的,这是另一个
  6. 是的,明白了,谢谢
  7. 但开始时这是非常愚蠢的。需要端口的进程应该只是打开它。当它已经打开端口而不是之前,它应该将端口号传递给另一方。