Winsock tcp / ip Socket听但连接被拒绝,竞争条件?

时间:2010-04-24 22:55:10

标签: c# windows sockets tcp winsock2

这涉及两个自动单元测试,每个单元测试启动一个tcp / ip服务器,创建一个非阻塞套接字然后bind()和listen()s在select()的循环中连接并下载一些客户端数据

问题是它们在单独运行时工作正常,但在作为测试套件运行时,第二个测试客户端将无法与WSACONNREFUSED连接......

除非

它们之间有几秒钟的Thread.Sleep()?? !!!

有趣的是,在任何失败后连接每1秒进行一次重试循环。所以第二次测试循环一段时间,直到10分钟后超时。

在此期间,netstat -na显示正确的端口号处于服务器套接字的LISTEN状态。那么如果它处于监听状态?为什么不接受连接?

在代码中,有一些日志消息显示select NEVER甚至可以准备好读取套接字(这意味着在应用于侦听套接字时准备接受连接)。

显然,问题必须与完成一个测试之间的某些竞争条件有关,这意味着套接字每一端的close()和shutdown(),以及下一个测试的启动。

如果重试逻辑允许它在几秒钟后最终连接,那么这不会太糟糕。然而,它似乎被“弄糊涂”,甚至不会重试。

然而,由于一些奇怪的原因,侦听套接字SAYS它处于LISTEN状态,即使通过不断拒绝连接。

这意味着它是Windoze O / S实际上正在捕获SYN数据包并返回一个RST数据包(这意味着“拒绝连接”)。

我唯一看到此错误的时候是代码出现问题导致数百个套接字卡在TIME_WAIT状态。但事实并非如此。 netstat在任何给定时刻仅显示大约十二个套接字,在TIME_WAIT中只有1或2个。

请帮忙。

3 个答案:

答案 0 :(得分:2)

我在各种具有各种内核的Windows操作系统(XP到Windows 7)的构建计算机上运行了大量这样的测试,我从未发现它是一个问题。

我不相信过渡到TIME_WAIT的监听套接字可能是你的问题;我当然没见过它,我经常在TIME_WAIT延迟期内启动和停止服务器的同一端口运行客户端服务器测试。

如果您在第一个服务器关闭其套接字之前启动了第二个服务器(或者,如果套接字在TIME_WAIT中),那么当您尝试{{1}时,我希望您的第二个服务器出错}})。

就我个人而言,我认为代码中存在接受连接的问题的可能性更大 - 那就是您的测试可能发现了错误;)

我们可以查看一下listen和accept循环之间的代码吗?

如果你颠倒了测试的顺序,你有问题吗?

客户端和服务器是否在同一台机器上运行,如果不是,它会改变吗?

我有一些TCP测试工具http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html,如果您设置测试系统以从该链接运行测试客户端,而不是来自此http://www.lenholgate.com/blog/2005/11/simple-echo-servers.html的示例服务器,您是否还能看到问题? (也就是说,在我的测试系统中使用我的客户端运行我的服务器,以便它运行它与运行你的东西一样,并且我的东西​​是否正常工作?)。

答案 1 :(得分:2)

然后根本问题在于关闭套接字,一个线程试图读取任何剩余的字节。这是作为一个单独的线程完成的,它将套接字的读端保持固定的毫秒时间,同时反复尝试读取任何数据。

该逻辑已被替换为更智能地读取任何数据并在读取返回0时正确关闭。因此它关闭得更快。

所以事实证明在我自己的代码中不正确地关闭套接字。

感谢您的帮助!

答案 2 :(得分:1)

来自This MSDN site

  

TIME_WAIT状态确定TCP释放已关闭的连接并重用其资源之前必须经过的时间。关闭和释放之间的这个间隔称为TIME_WAIT状态或2MSL状态。在此期间,与建立新连接相比,可以以比客户端和服务器低得多的成本重新打开连接。 TIME_WAIT行为在RFC 793中指定,该行为要求TCP保持闭合连接的间隔至少等于网络的最大段寿命(MSL)的两倍。释放连接时,其套接字对和用于套接字的内部资源可用于支持另一个连接。

     

Windows TCP在关闭连接后恢复到TIME_WAIT状态。处于TIME_WAIT状态时,无法重复使用套接字对。 TIME_WAIT周期可通过修改以下表示TIME_WAIT周期的DWORD注册表设置来配置。

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters\TcpTimedWaitDelay
  

默认情况下,MSL定义为120秒。 TcpTimedWaitDelay注册表设置默认值为240秒,表示最大段生命周期为120秒或4分钟的2倍。但是,您可以使用此条目自定义间隔。减少此条目的值允许TCP更快地释放已关闭的连接,从而为新连接提供更多资源。但是,如果该值太低,TCP可能会在连接完成之前释放连接资源,从而要求服务器使用其他资源来重新建立连接。此注册表设置可以设置为0到300秒。

我认为您可以将值设置为最小值为30(尝试更小但可能无效)

您可以查看Winsock Programmer's FAQ以获取更详细的说明。