背景
我在一台机器上运行TCP服务器,在通过TCP连接的不同机器上有多个客户端,我正在使用Wireshark监控网络流量,以及从我的服务器应用程序内部进行日志记录,以及通过System.Diagnostics tracelistener进行监控详细模式下的System.Net.Sockets。
问题:
由于一些意外的断开连接而提示检查我的日志,我看到一些非常奇怪的行为。根据服务器应用程序日志和System.Diagnostic输出日志,我的服务器使用开始/结束发送向客户端发送一个4字节的数据包。 BeginSend完成,EndSend也完成说它成功发送了4字节数据包。
但是,当我查看Wireshark日志时,该数据包永远不会出现。我在服务器计算机上运行Wireshark,因此应该没有理由将数据包显示在我的服务器和跟踪日志中,而不是在同一台机器上的Wireshark日志中。
此外,在所谓的成功发送数据包后(约30秒后)发生意外断开连接,这是由我服务器的EndReceive方法上的SocketException引起的。但是,在尝试从服务器发送之间的时间内,服务器正在确认从客户端收到的数据包,因此我知道连接仍处于活动状态。
有没有人有类似的经历,或者知道可能导致此问题的错误或什么?
我不愿意认为这是在套接字级别发生的,其中TCP表示我的数据包在它从未进入线路时发送,这意味着我不能依赖TCP作为可靠的传输(这当然是TCP的全部要点。
记录样本
从我的服务器应用程序:
2011-09-07 10:41:38,812 Attempting to send Packet (BeginSend - 4 bytes)
2011-09-07 10:41:38,812 Sent Packet (EndSend - 4 bytes)
从System.Diagnostics跟踪日志:
System.Net.Sockets Verbose: 0 : [4376] Socket#19699911::BeginSend()
DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [0980] Data from Socket#19699911::PostCompletion
DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [0980] 00000000 : 02 04 00 00 : ....
DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Socket#19699911::EndSend(OverlappedAsyncResult#44209720)
DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Exiting Socket#19699911::EndSend() -> 4#4
DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Exiting Socket#19699911::BeginSend() -> OverlappedAsyncResult#44209720
DateTime=2011-09-07T17:41:38.8125000Z
我也会粘贴Wireshark日志,但基本上当时该设备的接口上没有注册,除了来自客户端的数据包以及来自服务器的相应确认。
修改 根据要求,这是发送的代码(缩短空间和其他原因)。非常简单,对可能出错的任何事情都没有多大帮助。
在我的BeginSend方法中:
socket.BeginSend(data, 0, data.Length, SocketFlags.None, EndSend, state);
在我的EndSend方法中:
bytesSent = socket.EndSend(ar);
注意:这不是我的第一个牛仔竞技表,正如他们所说的......过去15年来,我一直在使用TCP套接字编写服务器和客户端,而且之前从未体验过这种情况。
此外,我使用的.NET版本是4.0 ...如果这有任何相关性。
帮助!
答案 0 :(得分:0)
我在.NET中使用套接字编程遇到的一个问题与垃圾收集有关。我的代码是在我的方法中创建一个套接字并分配给一个局部变量,而不是分配给一个成员变量。然后对套接字进行垃圾收集,导致SocketException
。显然,执行BeginSend
还不足以保存对该套接字的引用。
将套接字移动到成员变量为我解决了这个问题。希望这与您遇到的问题相关。
答案 1 :(得分:0)
我不愿意认为这是在套接字级别发生的, TCP表示我的数据包从未发送过时发送的地方 在线上,这意味着我不能依赖TCP作为 可靠的传输(当然这是TCP的重点)。
此声明不正确。仅仅因为您成功写入套接字并不意味着客户端接收到数据甚至离开了您的计算机。它只是意味着它已成功写入内部TCP / IP缓冲区。 TCP / IP将在其认为合适的情况下以尽可能多的块/帧发送该数据。如果您发送的数据很小,TCP / IP会延迟尝试将其他数据聚合到帧中,这尤其正确。
如果您没有在Wireshark中看到它,那么您可能没有在正确的界面上搜索,设置了过滤器,或某种类型的防火墙阻止您发送数据。看一下所有的反病毒或其他layere服务提供商,看看谁可以进入那里。
答案 2 :(得分:0)
如果可以忽略其限制,您是否可以重写应用程序以使用TcpClient
而不是Socket
?如果您的应用程序无论如何都绑定到TCP / IP,至少对于这个特定的套接字,您也可以使用抽象 - 它可能会有所帮助。此外,您可以尝试使用EndSend(IAsyncResult, SocketError)
重载来查看SocketError
对象是否包含任何有用的内容。
如果这些软件调整都没有帮助,我必须同意问题必须低于.NET软件级别,即防火墙软件(或硬件),防病毒软件等。
答案 3 :(得分:0)
这个问题很久以前就已存在,所以你可能已经开始......如果其他人有同样的问题,你可能想检查一下Windows“Memory Pressure Protection是否可能会被踢。这会导致当有多个同时连接时要丢弃的数据包,这就是你所看到的。
您可以尝试的另一个实验是暂时关闭服务器计算机上的防火墙。这也将关闭所有这些保护机制(如果我没有记错的话),如果事情有效,你知道其中一个是罪魁祸首。