6

我有一个客户端 .NET 应用程序和一个服务器 .NET 应用程序,通过套接字连接。

客户端每 500 毫秒发送一个包含 20 个左右字符的字符串。

在我的本地开发机器上,这工作得很好,但是一旦客户端和服务器在两个不同的服务器上,服务器在发送时不会立即接收到字符串。客户端仍然可以完美发送,我已经通过 Wireshark 确认了这一点。我还确认服务器确实每 500 毫秒接收一次字符串。

问题是我正在等待消息的服务器应用程序实际上只每 20 秒左右接收一次消息 - 然后它接收这 20 秒的所有内容。

我使用异步套接字,出于某种原因,回调只是不会每 20 秒调用一次以上。

AcceptCallback它建立连接并调用BeginReceive

handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);

这适用于我的本地机器,但在我的生产服务器上,ReadCallback 不会立即发生。

BufferSize 设置为 1024。我也尝试将其设置为 10。它会在调用 ReadCallback 后一次从套接字读取多少数据有所不同,但这并不是真正的问题。一旦它调用 ReadCallback,其余的工作正常。

我正在使用 Microsoft 的异步服务器套接字示例,因此您可以在那里看到我的 ReadCallback 方法的样子。

当数据到达服务器时,如何立即获取 BeginReceive 回调?

--

更新

这已经解决了。这是因为服务器只有一个处理器和一个核心。添加另一个核心后,问题立即解决。现在,当调用通过服务器时立即调用 ReadCallback。

谢谢大家的建议!!

4

3 回答 3

7

一种方法可能是调整发送端的 SO_SNDBUF 选项。因为当服务器/客户端都在同一个盒子上时你没有遇到这个问题,所以有一个小的缓冲区可能会限制发送端,因为(可能)服务器之间的发送速度较慢。如果发送方发送的速度不够快,那么发送端缓冲区可能会很快被填满。

更新:我们做了一些调试,结果发现问题在于应用程序变慢了。

于 2013-08-24T13:16:32.873 回答
6

可能是 Nagle 算法正在发送方等待更多数据包。如果您要发送小块数据,它们将合并为一个,因此您无需为小数据支付巨大的 TCP 标头开销。您可以使用禁用它:StreamSocketControl.NoDelay 请参阅:http: //msdn.microsoft.com/en-us/library/windows/apps/windows.networking.sockets.streamsocketcontrol.nodelay

Nagle 算法可能因环回而被禁用,这可能解释了为什么当您在同一台机器上同时拥有发送者和接收者时它会起作用。

于 2013-08-24T13:52:48.113 回答
1

应 OP 的要求,在此处复制我的“评论/答案”。

我的猜测是,问题出现是因为单核机器上的线程调度。这是一个老问题,在现代超线程/多核处理器时代几乎绝迹。当一个线程在程序执行过程中产生时,它需要预定的时间来运行。

在单核机器上,如果一个线程继续执行而没有明确地将控制权传递给 OS 调度程序(通过等待互斥体/信号或通过调用 Sleep),则任何其他线程(在同一进程中且具有较低优先级)的执行可能被调度程序无限期推迟。因此,在所描述的情况下,异步网络线程(很可能)只是缺乏执行时间——不时地只得到片段。

显然,添加第二个 CPU/核心通过提供并行调度环境来解决这个问题。

于 2013-09-11T09:21:36.333 回答