2

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

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

除非

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

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

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

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

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

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

然而,由于某种奇怪的原因,监听套接字说它处于 LISTEN 状态,即使一直拒绝连接。

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

我唯一一次看到这个错误是当代码出现问题导致数百个套接字卡在 TIME_WAIT 状态时。但这里不是这样。netstat 在任何给定时刻仅显示大约十几个套接字,其中 TIME_WAIT 中只有 1 或 2 个。

请帮忙。

4

3 回答 3

2

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

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

所以结果证明是我自己的代码中不正确地关闭了套接字。

感谢所有的帮助!

于 2010-05-23T21:06:28.670 回答
2

我在具有不同内核数量的各种 Windows 操作系统(XP 到 Windows 7)的构建机器上运行了很多这样的测试,但我从未认为这是一个问题。

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

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

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

我们可以看看你的监听和接受循环之间的代码吗?

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

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

等等。

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

于 2010-04-25T16:15:06.140 回答
1

这个 MSDN 网站

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以获得更详细的解释。

于 2010-04-25T05:22:17.693 回答