我知道TIME_WAIT是TCP/IP的一个组成部分,但是在SO(和其他地方)有很多问题,每秒创建多个套接字,服务器最终耗尽短暂的端口.
我发现的是,当使用TCPClient(或者Socket就此而言)时,如果我调用了Close()或者Dispose()方法,则套接字的TCP状态变为TIME_WAIT并且将在完全关闭之前考虑超时时间.
但是,如果只是将变量设置null为套接字将在下一次GC运行时完全关闭,这当然可以强制执行,而不会经历TIME_WAIT状态.
这对我来说没有多大意义,因为这是一个IDisposable对象不应该GC也调用Dispose()对象的方法?
这是一些PowerShell代码,演示了(在这台机器上没有安装VS).我使用Sysinternals的TCPView实时检查套接字状态:
$sockets = @()
0..100 | % {
$sockets += New-Object System.Net.Sockets.TcpClient
$sockets[$_].Connect('localhost', 80)
}
Start-Sleep -Seconds 10
$sockets = $null
[GC]::Collect()
Run Code Online (Sandbox Code Playgroud)
使用此方法,套接字永远不会进入TIME_WAIT状态.同样的,如果我只是手动调用之前关闭该应用程序Close()或Dispose()
有人可以解释一下是否这是一个好习惯(我想人们会说这不是).
编辑
GC已经回答了这个问题,但我仍然有兴趣找出为什么这会对套接字状态产生任何影响,因为这应该由操作系统控制,而不是.NET.
还有兴趣了解使用此方法来防止TIME_WAIT状态并最终是否是某个地方的错误(即,所有套接字是否应该通过TIME_WAIT状态?)是否是一个好习惯?
在创建,使用和处理多个HttpClient时,我注意到在TIME_WAIT状态下仍有套接字处于打开状态.
例如,运行以下代码后:
using System.Net.Http;
namespace HttpClientTest
{
public class Program
{
public static void Main(string[] args)
{
for (var i = 0; i < 10; i++)
{
using (var httpClient = new HttpClient())
{
var result = httpClient.
GetAsync("http://stackoverflow.com/").
Result;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我注意到netstat,套接字是打开的:
TCP 10.200.60.168:2722 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2751 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2752 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2753 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2754 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2755 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2756 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2757 151.101.193.69:http TIME_WAIT
TCP 10.200.60.168:2758 …Run Code Online (Sandbox Code Playgroud)