Open kaiohenrique opened 4 months ago
Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.
Why do you set ownsSocket: false
? AFAIK the behavior can change based on the ownership. cc @tmds
Hi, @wfurt
In this case, I want to avoid the NetworkStream.Dispose to execute the Socket.InternalShutdown method. Overriding the NetworkStream.Dispose method with ownsSocket: false
and only performing the Socket.Close and Socket.Dispose seems to workaround the issue and LingerOption is correctly applied. Is that a valid workaround?
Hi, @wfurt @tmds I need help to understand if avoiding Socket.InternalShutdown is a valid workaround so LingerOption works as expected. In our tests, avoiding the call to Socket.InternalShutdownm with LingerOptions(true, 0) got rid of connections in time_wait state completly. Are we missing any side effect?
Consider that requests has Connection:close to avoid connection pooling, a customer requeriment
Update: I have seen this behavior LingerOption(true,0)
_socket.Shutdown(SocketShutdown.Receive); //avoid time_wait and LingerOption is respected _socket.Shutdown(SocketShutdown.Send); //lots of sockets in time_wait _socket.Shutdown(SocketShutdown.Both); //lots of sockets in time_wait _socket.Close(); _socket.Dispose();
Triage: Not critical for 9.0. Moving to the future.
I can't reproduce this on Linux (Fedora 39).
I'm using this code to try to reproduce the issue:
string host = args.Length > 0 ? args[0] : "www.microsoft.com";
for (int i = 0; i < 10; i++)
{
Socket clientSocket = new Socket(SocketType.Stream, ProtocolType.Tcp)
{
NoDelay = true,
LingerState = new LingerOption(true, 0)
};
Console.WriteLine($"Connecting to '{host}'");
await clientSocket.ConnectAsync(new DnsEndPoint(host, 80));
System.Console.WriteLine($"Connect succeeded from {clientSocket.LocalEndPoint}!");
NetworkStream ns = new NetworkStream(clientSocket, ownsSocket: true);
ns.Dispose();
System.Console.WriteLine($"Disposed.");
}
When I comment out the LingerState = new LingerOption(true, 0)
line, I get sockets in the TIME_WAIT
state when the program is done. When I keep the line, they are gone.
Hi, @tmds Are you able to reproduce adding a Task.Delay after the loop?
Are you able to reproduce adding a Task.Delay after the loop?
No, also when the program doesn't exit, setting the new LingerOption(true, 0)
option results in there being no TIME_WAIT
sockets.
I can't reproduce the issue (on Fedora Linux).
Description
We have set LingerOption to avoid TIME_WAIT socket state but it seems not change the behavior. Extending NetworkStream and calling socket Close and Dispose seems to be doing the trick. No sure why Socket.InternalShutdown is impedind the LingerOption to work as expected. Am I missing anything here? Note: in the the request headers, we are sending "Connect: close" to avoid pooling
Reproduction Steps
SocketsHttpHandler ConnectCallback overwrite
OverrideNetworkStream override the NetworkStream.Dispose as a wokaround because Socket.InternalShutdown seems to be causing the LingerOptions to not work as expected
Expected behavior
NetworkStream should respect LingerOptions
Actual behavior
As NetworkStream is calling Socket.InternalShutdown, LingerOption is not being respected and socket is leaking in TIME_WAIT state
Regression?
Only tested in .Net8 both in Windows and Linux
Known Workarounds
No response
Configuration
No response
Other information
No response