背景:
我在一台计算机上运行 TCP 服务器,并在通过 TCP 连接的不同计算机上运行多个客户端,并且我正在使用 Wireshark 以及从我的服务器应用程序内部进行日志记录来监视网络流量,并通过System.Net.Sockets 上详细模式下的 System.Diagnostics 跟踪侦听器。
问题:
由于一些意外的断开连接,提示我检查我的日志,我看到一些非常奇怪的行为。根据服务器应用程序日志和 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...如果有任何相关的话。
帮助!
Background:
I am running a TCP server on one machine with multiple clients on separate machines connecting over TCP, and I am monitoring network traffic with Wireshark, as well as with logging from within my server application, and through the System.Diagnostics tracelistener on System.Net.Sockets in verbose mode.
Problem:
Prompted to examine my logs due to some unexpected disconnects, I see some very strange behavior. According to the server application logs, and the System.Diagnostic output logs, my server is sending a 4 byte packet to a client using begin/end send. The BeginSend completes, and the EndSend also completes saying that it successfully sent the 4 byte packet.
However, when I look at the Wireshark logs, that packet never shows up. I am running Wireshark on the server machine, so there should be no reason for the packet to show up in my server and trace logs, but not in the Wireshark logs on the same machine.
Also, there is an unexpected disconnect that occurs soon after the supposedly successful packet send (~30 seconds later), which is caused by a SocketException on my server's EndReceive method. But during the time between the attempted send from the server, the server is acknowledging packets received from the client, so I know the connection is still active.
Has anyone out there had a similar experience, or know of a bug or something that might be causing this?
I would hate to think that this is occurring at the socket level, where TCP is saying that my packet is sent when it never even made it onto the wire, which would mean that I cannot rely on TCP as a reliable transport (which of course is the whole point of TCP).
Log Samples
From my server application:
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)
From the System.Diagnostics trace log:
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
I would paste the Wireshark logs, too, but essentially there is nothing registering on the interface for that device at that time, except for the packets coming from the client, and the corresponding acknowledgments from the server.
Edit:
As requested, here is the code for the send (shortened for space, and other reasons). Pretty simple, not much in the way of anything that could go wrong.
In my BeginSend method:
socket.BeginSend(data, 0, data.Length, SocketFlags.None, EndSend, state);
In my EndSend method:
bytesSent = socket.EndSend(ar);
Note: This is not my first rodeo, as they say... I have been writing servers and clients using TCP sockets for the last 15 years, and have never experienced this before.
Also, the version of .NET that I am using is 4.0... if that is of any relevance.
Help!
发布评论
评论(4)
我在 .NET 中进行套接字编程时遇到的一个问题与垃圾收集有关。我的代码是创建一个套接字并在我的方法中分配给局部变量,而不是分配给成员变量。然后套接字被垃圾收集,导致 SocketException。显然,执行
BeginSend
不足以保存对该套接字的引用。将套接字移动到成员变量为我解决了这个问题。希望这与您遇到的问题相关。
One issue I've encountered with socket programming in .NET was related to garbage collection. My code was creating a socket and assigning to a local variable in my method instead of assigning to a member variable. The socket was then garbage-collected, causing a
SocketException
. Apparently, doing aBeginSend
wasn't enough to hold a reference to that socket.Moving the socket to a member variable solved the issue for me. Hopefully this is relevant to the issue you're encountering.
这种说法是不正确的。仅仅因为您成功写入套接字并不意味着数据已被客户端接收或什至离开您的计算机。这仅意味着它已成功写入内部 TCP/IP 缓冲区。 TCP/IP 将以它认为合适的尽可能多或尽可能少的块/帧发送该数据。如果您发送的数据很小,则尤其如此,TCP/IP 将延迟尝试将其他数据聚合到帧中。
如果您在 Wireshark 中没有看到它,那么您可能没有在正确的接口上侦听、设置了过滤器,或者某种防火墙阻止您发送数据。查看现有的防病毒软件或其他分层服务提供商,看看谁可以进入那里。
This statement is incorrect. Just because you successfully write to a socket does not mean that data was received by the client or even left your machine. It just means it was successfully written to the internal TCP/IP buffers. TCP/IP will send that data in as many or as few blocks/frames as it deems fit. This is especailly true if the data you are sending is small, TCP/IP will delay to try to aggregate additional data into the frame.
If you are not seeing it in Wireshark, then you are likely not listening on the right interface, have a filter set, or a firewall of some sort is preventing you from sending the data. Take a look at any antivirous or other layere service providers in place to see who could be getting in there.
如果可以忽略其限制,您是否可以重写应用程序以使用
TcpClient
而不是Socket
?如果您的应用程序无论如何都绑定到 TCP/IP,至少对于这个特定的套接字,您不妨使用抽象 - 它可能会有所帮助。另外,您可以尝试使用EndSend(IAsyncResult, SocketError)
重载以查看 SocketError
对象是否包含任何有用的内容。如果这些软件调整都没有帮助,我必须同意问题一定低于 .NET 软件级别,即防火墙软件(或硬件)、防病毒软件等。
If it's possible to disregard its limitations, would it be possible for you to rewrite the application to use
TcpClient
instead ofSocket
? If your app is bound to TCP/IP anyway, at least for this particular socket, you might as well use the abstraction -- it might help. Also, you could try to use theEndSend(IAsyncResult, SocketError)
overload to see if theSocketError
object contains anything useful.If none of these software tweaks helps, I have to agree that the problem must be below the .NET software level, i.e. in firewall software (or hardware), antivirus, etc.
好吧,这个问题已经是很久以前的事了,所以您可能已经继续前进了...如果其他人也遇到同样的问题,您可能需要检查 Windows 是否内存压力保护 可能会启动。当有多个同时连接时,这将导致数据包被丢弃,这就是您所看到的。
您可以尝试的另一个实验是暂时关闭服务器计算机上的防火墙。这也将关闭所有这些保护机制(如果我没记错的话),如果一切正常,你就知道其中之一是罪魁祸首。
Well this question was ages ago, so you've probably moved on... in case someone else has the same problem, you may want to check whether Windows' Memory Pressure Protection might be kicking in. This will cause packets to be dropped when there are multiple simultaneous connections, which is what you're seeing.
Another experiment you can try is to temporarily turn off the firewall on your server machine. This will also turn off all of these protection mechanisms (if I'm not mistaken) and if things work then, you know that one of those is the culprit.