cog*_*el0 12 .net c# sockets powershell
我知道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状态?)是否是一个好习惯?
这对我来说没有多大意义,因为这是一个IDisposable对象,不应该GC也调用对象的Dispose()方法?
的Dispose模式,也被称为IDisposable的,提供了一种用于非托管对象被清理的两种方式.Dispose方法提供了一种直接快速的清理资源的方法.由垃圾收集器调用的finalize方法是一种故障安全方法,用于确保清除非托管资源,以防其他开发人员使用代码忘记调用Dispose方法.这有点类似于C++开发人员忘记在堆分配的内存上调用Delete - 这会导致内存泄漏.
根据引用的链接:
"尽管终结器在某些清理方案中很有效,但它们有两个明显的缺点:
当GC检测到对象符合收集条件时,将调用终结器.这在不再需要资源之后的某个未确定的时间段发生.开发人员可能或者想要释放资源的时间与终结器实际释放资源的时间之间的延迟在获取许多稀缺资源(可能容易耗尽的资源)的程序中或者在资源的情况下可能是不可接受的.保持使用是昂贵的(例如,大的非托管内存缓冲区).
当CLR需要调用终结器时,它必须推迟对象内存的收集,直到下一轮垃圾收集(终结器在集合之间运行).这意味着对象的内存(以及它引用的所有对象)将不会被释放更长的时间."
使用此方法,套接字永远不会进入TIME_WAIT状态.如果我在手动调用Close()或Dispose()之前关闭应用程序,则相同
有人可以解释一下是否这是一个好习惯(我想人们会说这不是).
关闭它需要一段时间的原因是因为默认情况下代码会延迟给应用程序一些时间来处理任何排队的消息.根据MSDN上的TcpClient.Close方法doc:
"Close方法将实例标记为已配置,并请求关联的Socket关闭TCP连接.基于LingerState属性,在调用Close方法后,当数据仍有待发送时,TCP连接可能会保持打开一段时间.底层连接完成关闭时未提供通知.
调用此方法最终将导致关联的Socket关闭,并且还将关闭用于发送和接收数据的相关NetworkStream(如果已创建).
可以通过以下代码减少或完全消除此超时值:
// Allow 1 second to process queued msgs before closing the socket.
LingerOption lingerOption = new LingerOption (true, 1);
tcpClient.LingerState = lingerOption;
tcpClient.Close();
// Close the socket right away without lingering.
LingerOption lingerOption = new LingerOption (true, 0);
tcpClient.LingerState = lingerOption;
tcpClient.Close();
Run Code Online (Sandbox Code Playgroud)
还有兴趣了解使用此方法来防止TIME_WAIT状态并最终是否是某个地方的错误(即,所有套接字是否应该通过TIME_WAIT状态?)是否是一个好习惯?
至于将对TcpClient对象的引用设置为null,建议的方法是调用Close方法.当引用设置为null时,GC最终调用finalize方法.finalize方法最终调用Dispose方法以合并代码以清理非托管资源.因此,它将关闭套接字 - 它只是不推荐.
在我看来,这取决于应用程序是否应该允许一些逗留时间给应用程序时间来处理排队的消息.如果我确定我的客户端应用程序已经处理了所有必要的消息,那么如果我认为将来可能会改变,我可能会给它一个0秒或者1秒的逗留时间.
对于非常繁忙的客户端和/或弱硬件 - 那么我可能会给它更多时间.对于服务器,我必须在负载下对不同的值进行基准测试.
其他有用的参考:
有没有TcpClient.Close或Socket.Close(0)可以阻止我的代码的情况?
| 归档时间: |
|
| 查看次数: |
2536 次 |
| 最近记录: |