WIndows 7上的高频数据侦听器TCP过载

时间:2011-12-20 16:56:37

标签: windows sockets networking tcp

我编写了一个基于c#的侦听器来从股票市场服务器检索数据。 问题是,在通过WireShark进行监控之后,TCP窗口变满了,这意味着接收主机(我)在处理传入数据时遇到了问题。

我知道我的数据提供者已禁用他身边的TCP确认,所以基本上他只是推送TCP数据包并查看它们是否“仍然存在”:如果他检测到在一定时间后没有处理它们,则只需关闭连接

我真的不知道该怎么做,我已经禁用了Windows 7的Auto Scale Tuning和Heuristics,但这没有任何效果。我还注意到在Windows 7上无法设置TPC Windows大小(RWIN)。

我知道这不是一个与编程相关的问题本身,但它是以某种方式,因为从代码的角度来看,这是至关重要的。

修改
响应者说:“你的应用程序并没有足够快地提取数据” 这很有意思,但我对如何优化它没有真正的想法:

    private class IoContext
    {
        // The socket used for the operation:
        public Socket _ipcSocket;
        // The buffer used for the operation:
        public VfxMsgBlock _ipcBuffer;

        public IoContext(Socket socket, VfxMsgBlock buffer)
        {
            _ipcSocket = socket;
            _ipcBuffer = buffer;
        }
    }

    private void InitiateRecv(IoContext rxContext)
    {
        rxContext._ipcSocket.BeginReceive(rxContext._ipcBuffer.Buffer, rxContext._ipcBuffer.WrIndex,
            rxContext._ipcBuffer.Remaining(), 0, CompleteRecv, rxContext);
    }

    private void CompleteRecv(IAsyncResult ar)
    {
        IoContext rxContext = ar.AsyncState as IoContext;
        if (rxContext != null)
        {
                int rxBytes = rxContext._ipcSocket.EndReceive(ar);
                if (rxBytes > 0)
                {
                    //Adjust the write index in the message block:
                    rxContext._ipcBuffer.WrIndex = rxContext._ipcBuffer.WrIndex + rxBytes;

                    //(...) Do Stuf here with data                        

                    rxContext._ipcBuffer.Crunch();

                    //Initiate another asynchronous read:
                    InitiateRecv(rxContext);
                }                
          }
     }

编辑2
回应Len Holgate:

我通过c#属性直接更改/检查了Recv Buffer大小(使用GetSocketOption / SetSocketOption遇到了一些麻烦)

当我改变套接字缓冲区大小时,我会注意到性能稍有变化,即连接在10mn后用大缓冲区(1000000)而不是3分钟(使用10240或更低(甚至0,我不知道为什么......)下降。奇怪))

这是我得到的第一个WireShark日志:

[SYN, ACK] Seq=0 Ack=1 Win=5840 Len=0 MSS=1380 SACK_PERM=1 WS=128

它不会改变Socket的接收缓冲区大小

关于Windows 7& TCP Windows大小,我的意思是在Windows中重写TCP管理导致它自动缩放,并且没有可用于“手动”设置它的注册表参数。
但是,你是对的:在每个插槽的基础上,它可以使用接收缓冲区大小进行调整 来源here

3 个答案:

答案 0 :(得分:2)

如果在TCP中禁用ack处理,则不再使用TCP了。你正在使用一些看起来有点像TCP的奇怪的frankenprotocol。

通常你应该使用Windows TCP自动调整 - 它是相当不错的,虽然它确实依赖于对等通话TCP(在你的情况下它不是)。

如果你需要防止窗口变满,你最好的办法就是更快地处理数据 - 很可能窗口正在填满,因为你的应用程序没有足够快地提取数据。精简应该是您的第一个停靠点。使用异步套接字是一个良好的开端,可以连续保持多个读取暂停,这样操作系统可以在准备就绪后立即将数据移交给您的应用程序,这将是朝着正确方向迈出的又一步。

最后,如果你想使用UDP,你应该尝试使用UDP而不是wierd TCP。

答案 1 :(得分:2)

您是否已将套接字的recv缓冲区设置为尽可能大?

请参阅此处了解如何影响TCP窗口大小:http://msdn.microsoft.com/en-us/library/ms819736.aspx

已编辑以显示我在1gb链接上使用两台win 7计算机获得的内容,未对默认设置进行更改,只需在侦听套接字上使用SO_RECVBUF设置setsockopt(),窗口大小通过连接的wireshark日志验证...实际窗口大小是根据公布的大小和缩放系数隐含的乘数计算的。

 Set Recv  |Advertised |Scaling|Multiply| Actual TCP |Difference|
   Buf to  |  Window   |       |  By    |Window size |          |
   --------+-----------+-------+--------+----------- +----------+
   default |   8192    |   8   |    256 |    2097152 |          | 
      1024 |   1024    |   0   |      1 |       1024 |         0|
     10240 |  10240    |   0   |      1 |      10240 |         0|
  66666666 |  65535    |  10   |   1024 |   67107840 |   -441174|
 666666666 |  65535    |  14   |  16384 | 1073725440 |-407058774|
1000000000 |  65535    |  14   |  16384 | 1073725440 | -73725440|
1073725440 |  65535    |  14   |  16384 | 1073725440 |         0|
1073741823 |  65535    |  14   |  16384 | 1073725440 |     16383|
1073741824 |   8192    |   8   |    256 |    2097152 |1071644672|
2147483647 |   8192    |   8   |    256 |    2097152 |2145386495|

所以,很明显,在Windows 7上可以影响每个插槽的TCP窗口大小。你能提供一个文件的链接,让你相信“从Windows 7开始我只是说那个没有可用于手动设置的TCP窗口大小(仅限自动调整netsh选项)“

请注意,在开始握手中传输窗口大小缩放时,必须在发出连接之前将recv buf设置应用于侦听套接字或出站套接字。

在所有情况下,对setsockopt()的调用成功,立即调用getsockopt()报告recv缓冲区为上一次调用setsockopt()时请求的大小。

请注意,虽然理论最大值是unsigned int的最大值2147483647,但实际最大有用值似乎是1073741823(0x3FFFFFFF),这可能因操作系统版本而异,但请记住立即调用{ {1}}返回了已设置的相同值,因此除了查看wireshark日志之外,它是不可能的,以确定1073741823以上的值被完全忽略(至少从窗口大小的角度来看)。

当然这需要连接对等体指定一个窗口缩放选项,甚至是0,以表明它接受窗口缩放。

请向我们展示初始握手包的wireshark连接日志。我可以提供您可以测试的编译代码,这是您想要的。

答案 2 :(得分:1)

作为一个额外的已经很好的答案,我建议进行以下测试:尽可能快地拉出数据并立即丢弃。这允许您查看您的处理速度是否真的是问题,或者它是否在其他地方。你不能更快地阅读和抛弃数据。