简体   繁体   English

以编程方式减少TIME_WAIT或CLOSE_WAIT

[英]Programmatically reducing TIME_WAIT or CLOSE_WAIT

In an .aspx page, I need to bind a socket to a port, use it, and then dispose of it. .aspx页中,我需要将套接字绑定到端口,使用它,然后处置它。 It works the first time, but the second time I access the page I get the following exception: 它第一次起作用,但是第二次访问该页面时,出现以下异常:

[Exception in bind: System.Net.Sockets.SocketException (0x80004005): Only one usage of each socket 
 address (protocol/network address/port) is normally permitted
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, 
 SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
[...]

This is the code, with the Exception triggering the error. 这是代码,其中Exception触发了错误。 Please note the fact that Accept() blocks is perfectly acceptable in my scenario. 请注意,在我的场景中,Accept()块是完全可以接受的。

IPAddress ipAddress = IPAddress.Parse(ip);
Socket s1 = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(ipAddress, port);
try {
    s1.Bind(ep);
} catch(Exception ex) {
    HttpContext.Current.Response.Write("[Exception in bind: "+ ex + "\n");
    return;
}
s1.Listen(32);
// block until there's a connection
Socket s2 = s1.Accept();
// save for later
Session["s1"] = s1;
Session["s2"] = s2;

The socket is retrieved through the Session and used later, and destroyed: 套接字是通过会话检索的,以后可以使用并销毁:

Socket s1 = Session["s1"] as Socket;
Socket s2 = Session["s2"] as Socket;

// ... use the socket ...

// cleanup
s2.Shutdown(SocketShutdown.Both);
s2.Disconnect(true);
s2.Close();
s2.Dispose();
s1.Shutdown(SocketShutdown.Both);
s1.Disconnect(true);
s1.Close();
s1.Dispose();

I've tried various combinations of flags such as Linger , ReuseAddress , ExclusiveAddressUse and values for the Listen backlog but nothing changes. 我尝试了标志的各种组合,例如LingerReuseAddressExclusiveAddressUseListen待办事项的值,但没有任何变化。

An important note: without the ReuseAddress option the socket is in TIME_WAIT as shown by netstat -ano . 重要说明:如果没有ReuseAddress选项,则套接字位于TIME_WAIT ,如netstat -ano所示。 When I use ReuseAddress , the socket is stuck in CLOSE_WAIT . 当我使用ReuseAddress ,套接字卡在CLOSE_WAIT

I am fully aware of the implications : is there a way to programmatically reduce the CLOSE_WAIT or TIME_WAIT intervals for a specific socket without having to touch the registry? 我完全了解其中的含义 :是否有一种方法可以以编程方式减少特定套接字的CLOSE_WAIT或TIME_WAIT间隔,而无需触摸注册表?

I'm wondering if I'm forgetting something when trying to dispose of the socket... 我想知道是否在尝试处置套接字时遗忘了一些东西...

It turns out that leveraging the Session object is not ideal. 事实证明,利用Session对象不是理想的选择。 The port would be left open after the first use, and according to the PID shown with netstat , an IIS Worker would own it. 首次使用后,该端口将保持打开状态,根据netstat显示的PID,IIS Worker将拥有该端口。 Therefore it appears like it's impossible to call Close() on it. 因此,似乎无法在其上调用Close()

The solution was to close the server socket ( s1 in my example) after Accept : 解决方案是在Accept之后关闭服务器套接字(在我的示例中为s1 ):

[...]
s1.Listen(32);
// block until there's a connection
Socket s2 = s1.Accept();
// *close the server socket*
s1.Close();
// only save s2 for later
Session["s2"] = s2;

Then use only s2 , for example: 然后仅使用s2 ,例如:

// ...later on
Socket s1 = Session["s1"] as Socket;
try {
    while ((bytesRead = s1.Receive(receiveBuffer)) > 0 ) {
        byte[] received = new byte[bytesRead];
        Array.Copy(receiveBuffer, received , bytesRead);
        Response.BinaryWrite(received);
    }
} catch(Exception ex){
[...]

The previous solution makes the "cleanup" unnecessary. 先前的解决方案使“清理”变得不必要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM