我认为你可能进行得太快了。
大多数操作系统在任何时候打开的套接字数量都有限制,但情况实际上比这更糟糕。
当一个套接字被关闭时,它会被放置在特殊的等待状态中,持续一定的时间。通常是两倍的数据包生存时间,并确保网络上没有仍在传输到您的套接字的数据包。
一旦该时间过期,您可以确信所有在网络中的数据包已经死亡。套接字被放置在特殊状态下,以便在关闭时在网络中的数据包可以被捕获并在其死亡之前到达时被丢弃。
我认为这就是你的情况,套接字没有像你想象得那么快地释放。
我们在代码中打开了许多短暂的会话,遇到类似的问题。它运行得很好,但随着硬件变得更快,可以在给定时间内打开更多会话。这表现为无法打开更多会话。
检查这一点的一种方法是从命令行执行 `netstat -a`,看看有多少会话实际上处于等待状态。
如果事实证明确实如此,有几种处理方法:
- 重用您的会话,手动或通过维护连接池。
- 在每个连接中引入延迟,以尝试阻止达到饱和点。
- 先全力以赴,直到达到饱和状态,然后再修改您的行为,例如将连接逻辑运行在重试最多 60 次、每次延迟两秒钟的 while 语句内。这使您可以以最大速度运行,仅在出现问题时降低速度。
最后一个项目需要一些扩展。在我们上述应用程序中,实际上使用了后退策略,如果资源提供者抱怨,它会逐渐减轻对该资源的负载,因此我们选择了一个一秒钟,然后两秒钟,然后四秒钟等的时间间隔,而不是 30 个两秒钟的延迟。
后退策略的常规过程如下,它可以用于任何可能存在资源临时短缺的情况。伪代码中暗示的操作将是在您的情况下打开套接字。
set maxdelay to 16
set maxtries to 10
set delay to 0
set tries to 0
while more actions needed:
if delay is not 0:
sleep delay
attempt action
if action failed:
add 1 to tries
if tries is greater than maxtries:
exit with permanent error
if delay is 0:
set delay to 1
else:
double delay
if delay is greater than maxdelay:
set delay to maxdelay
else:
set delay to 0
set tries to 0
这样做可以让进程在绝大多数情况下以最大速度运行,但当错误开始发生时会逐渐退避,希望能给资源提供者恢复的时间。延迟的逐步增加允许更严重的资源限制得到恢复,而最大尝试次数则捕获您所称的永久性错误(或需要过长时间才能恢复的错误)。