开发者

How to prevent .NET libraries from sending RST packet on close

I'm doing some testing trying to isolate some odd behavior in the libraries (.NET). When I use the Winsock API through C++ and simply call, closesocket(), I see the windows side send the FIN/ACK packet and the remote side send back an ACK packet. This is what I would call a graceful close. However, when programming in C# I'm not seeing what I would call a graceful close.

In C#, I open my socket and then, when closing it, I see windows send a FIN packet Only when first calling Socket.Shutdown(). However, regardless, when I call Socket.Close() in C#, an RST packet is sent and the connection summarily dropped. This confuses me because, from what I've read on line, the TCP closing process should be FIN/ACK -> ACK (from both sides actually but for now, I'm only concerned with "my" side); i.e. there should not be an RST packet in the mix at all. From what I've read, apparently, an RST packet is only sent when the receiver is uncertain about开发者_运维知识库 the connection state and wants out.

Why is this RST packet being sent on a planned shutdown in .NET and not at all in a planned shutdown from the winsock API? Is there a way to prevent the transmission of an RST packet during a graceful shutdown from .NET?

In case it's important, in both code paths, I'm reading all available data on the socket before calling the respective close() method.


Reading the .NET doc of Socket.Close, this is what I found:

For connection-oriented protocols, it is recommended that you call Shutdown before calling the Close method. This ensures that all data is sent and received on the connected socket before it is closed. If you need to call Close without first calling Shutdown, you can ensure that data queued for outgoing transmission will be sent by setting the DontLinger Socket option to false and specifying a non-zero time-out interval. Close will then block until this data is sent or until the specified time-out expires. If you set DontLinger to false and specify a zero time-out interval, Close releases the connection and automatically discards outgoing queued data.

which actually makes sense. If there's still data in the buffer (OS one) and you tear the connection down or kill the process the connection will be reset (more detailed information in the TCP specs).

As to when RST is sent check out TCP Guide.

My guess is that there is still some unset or in transit data or in outgoing/incomming buffers that triggers the RST.


Following code may prevent RST packet. It is because wait 60 seconds after sending a FIN packet.

socket.Close(60);

Close method description is here.


Just recently hit a similiar issue where an application was talking POP3 to an Exchange Server. When the .NET program finished, it closed down ungracefully, and Exchange treated the POP3 conversation as "aborted" and rolled it back.

The reason for that is I think TCP RST is a "one-way" message-- you don't have to wait for a reply. So that's what .NET sends (or perhaps any program after it terminates.) One possible solution is to wait a bit after closing the socket and before quitting the program:

Thread.Sleep(5000);

This worked for the POP3 problem I mentioned earlier; the waiting time caused the connection to shut down gracefully, and Exchange no longer aborted the session.


In a similar situation, I called socket.Disconnect(false) instead of socket.Close().

if (theSenderSocket != null){
    theSenderSocket.Disconnect(false);
   }

Then checking the Wireshark filters found that instead if RST/ACK, it was sending FIN/ACK.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜