Программно сокращая TIME_WAIT или CLOSE_WAIT - PullRequest
0 голосов
/ 18 мая 2018

На странице .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 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 'мы пробовали различные комбинации флагов, такие как Linger, ReuseAddress, ExclusiveAddressUse и значения для Listen backlog, но ничего не меняется.

Важное примечание: без опции ReuseAddress сокетв TIME_WAIT как показано netstat -ano.Когда я использую ReuseAddress, гнездо застревает в CLOSE_WAIT.

Я полностью осведомлен о последствиях : есть ли способ программно уменьшить интервалы CLOSE_WAIT или TIME_WAIT для конкретного сокета, не касаясь реестра?

Iмне интересно, забываю ли я что-то при попытке утилизировать розетку ...

1 Ответ

0 голосов
/ 18 мая 2018

Оказывается, использование объекта Session не является идеальным.Порт будет оставлен открытым после первого использования, и согласно PID, показанному с netstat, IIS Worker будет его владельцем.Поэтому кажется, что на нем невозможно вызвать Close().

Решением было закрыть сокет сервера (s1 в моем примере) после Accept:

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

Предыдущее решение исключает необходимость «очистки».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...