jjzjj

c# - 要关闭套接字,请不要 Close() 套接字。嗯?

coder 2024-05-30 原文

我知道 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()

使用此方法,套接字永远不会进入 TIME_WAIT 状态。如果我只是在手动调用 Close()Dispose()

之前关闭应用程序,情况也是如此

有人可以阐明并解释这是否是一种好的做法(我想人们会说这不是)。

编辑

GC 在此事中的利害关系已经得到解答,但我仍然有兴趣找出为什么这会对套接字状态产生任何影响,因为这应该由操作系统控制,而不是 .NET。

也有兴趣了解使用此方法来防止 TIME_WAIT 状态是否是一种好的做法,并最终确定这是否是某个地方的错误(即,所有套接字都应该进入 TIME_WAIT 状态吗?)

最佳答案

This doesn't make a lot of sense for me, since this is an IDisposable object shouldn't the GC also invoke the Dispose() method of the object?

Dispose pattern ,也称为 IDisposable,提供了两种清理非托管对象的方法。 Dispose 方法提供了一种直接且快速的方法来清理资源。由垃圾收集器调用的 finalize 方法是一种故障安全方法,可确保在使用该代码的其他开发人员忘记调用 Dispose 方法的情况下清理非托管资源。这有点类似于 C++ 开发人员忘记在堆分配的内存上调用 Delete - 这会导致内存泄漏。

根据引用的链接:

“尽管终结器在某些清理场景中很有效,但它们有两个明显的缺点:

  1. 当 GC 检测到对象符合收集条件时,将调用终结器。这发生在不再需要资源之后的某个不确定的时间段。开发人员可以或想要释放资源的时间与终结器实际释放资源的时间之间的延迟在获取许多稀缺资源(很容易耗尽的资源)的程序中或在资源不足的情况下可能是 Not Acceptable 保持使用的成本很高(例如,大型非托管内存缓冲区)。

  2. 当 CLR 需要调用终结器时,它必须将对象内存的收集推迟到下一轮垃圾收集(终结器在两次收集之间运行)。这意味着该对象的内存(以及它引用的所有对象)将在更长的时间内不会被释放。”

Using this method, the sockets never go into a TIME_WAIT state. Same if I just close the app before manually invoking Close() or Dispose()

Can someone shed some light and explain whether this would be a good practice (which I imagine people are going to say it's not).

它需要一段时间才能关闭的原因是因为代码 lingers by default给应用程序一些时间来处理任何排队的消息。根据TcpClient.Close MSDN 上的方法文档:

"Close 方法将实例标记为已处置,并请求关联的 Socket 关闭 TCP 连接。根据 LingerState 属性,当数据仍有待发送时,调用 Close 方法后 TCP 连接可能会保持打开状态一段时间. 底层连接完成关闭时不提供通知。

调用此方法最终将导致关联的 Socket 关闭,并且还将关闭用于发送和接收数据的关联 NetworkStream(如果已创建)。”

following code 可以减少或完全消除此超时值:

// 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();

Also interested in finding out whether it would be good practice to use this method to prevent TIME_WAIT states and ultimately whether this is a bug somewhere (i.e., should all sockets go through a TIME_WAIT state?)

至于将对 TcpClient 对象的引用设置为 null,推荐的方法是调用 Close 方法。当引用设置为 null 时,GC 最终调用 finalize 方法。 finalize 方法最终调用 Dispose 方法以合并清理非托管资源的代码。因此,它可以关闭套接字 - 只是不推荐这样做。

在我看来,是否应该允许一些延迟时间让应用有时间处理排队的消息取决于应用。如果我确定我的客户端应用程序已经处理了所有必要的消息,那么我可能会给它一个 0 秒或 1 秒的逗留时间,如果我认为将来可能会改变的话。

对于非常繁忙的客户端和/或薄弱的硬件——那么我可能会给它更多的时间。对于服务器,我必须在负载下对不同的值进行基准测试。

其他有用的引用资料:

What is the proper way of closing and cleaning up a Socket connection?

Are there any cases when TcpClient.Close or Socket.Close(0) could block my code?

关于c# - 要关闭套接字,请不要 Close() 套接字。嗯?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40785598/

有关c# - 要关闭套接字,请不要 Close() 套接字。嗯?的更多相关文章

  1. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  2. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  3. ruby - 如何关闭 ruby​​ gem "Spreadsheet?"中的文件 - 2

    下面的代码在我第一次运行它时就可以正常工作:require'rubygems'require'spreadsheet'book=Spreadsheet.open'/Users/me/myruby/Mywks.xls'sheet=book.worksheet0row=sheet.row(1)putsrow[1]book.write'/Users/me/myruby/Mywks.xls'当我再次运行它时,我会收到更多消息,例如:/Library/Ruby/Gems/1.8/gems/spreadsheet-0.6.5.9/lib/spreadsheet/excel/reader.rb:11

  4. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  5. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  6. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  7. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  8. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  9. ruby - 如何在 watir 测试套件结束时关闭浏览器? - 2

    使用ruby​​的watir测试网络应用程序时,浏览器最后会保持打开状态。网上的一些建议是,要进行真正的单元测试,您应该在每次测试时(在拆卸调用中)打开和关闭浏览器,但这很慢而且毫无意义。或者他们做这样的事情:defself.suites=superdefs.afterClass#Closebrowserenddefs.run(*args)superafterClassendsend但这会导致摘要输出不再显示(诸如“100次测试、100次断言、0次失败、0次错误”之类的内容仍应显示)。我怎样才能让ruby​​或watir在我的测试结束时关闭浏览器? 最佳答案

  10. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

随机推荐