【问题标题】:Programmatically reducing TIME_WAIT or CLOSE_WAIT以编程方式减少 TIME_WAIT 或 CLOSE_WAIT
【发布时间】:2018-10-28 15:17:43
【问题描述】:

在.aspx 页面中,我需要将套接字绑定到端口,使用它,然后将其丢弃。它第一次工作,但我第二次访问该页面时出现以下异常:

[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)
[...]

这是代码,异常触发错误。请注意,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;

socket通过Session取回,稍后使用,销毁:

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

我尝试了各种标志组合,例如 Linger、ReuseAddress、ExclusiveAddressUse 和 Listen 积压的值,但没有任何变化。

重要说明:没有ReuseAddress 选项,套接字位于TIME_WAIT 中,如netstat -ano 所示。当我使用ReuseAddress 时,套接字卡在CLOSE_WAIT 中。

我完全了解其中的含义:有没有办法以编程方式减少特定套接字的 CLOSE_WAIT 或 TIME_WAIT 间隔,而无需接触注册表?

我想知道我在尝试处理套接字时是否忘记了什么......

【问题讨论】:

    标签: c# asp.net sockets


    【解决方案1】:

    事实证明,利用 Session 对象并不理想。该端口在第一次使用后将保持打开状态,并且根据netstat 显示的 PID,IIS Worker 将拥有它。因此,似乎无法在其上调用Close()。

    解决方案是在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;
    

    然后只使用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){
    [...]
    

    之前的解决方案使得“清理”变得不必要了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多