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