C# TcpClinet LingerOption с функцией Close() не пропускает TIME_WAIT

#c# #sockets #tcp #tcpclient

Вопрос:

Я пытаюсь связаться с сервером с помощью C# TcpClient в течение длительного времени. Например, я подключаюсь к серверу на 5 секунд, отключаюсь, затем пытаюсь подключиться к серверу через 10 секунд и повторяю…

Но в том случае, если я установил параметр LingerOption и ResueAddress как true, при повторном подключении к серверу появилась функция ExtendedSocketExcption.

Вот мой код. (.Net5, Windows 10)

         TCPSocket = new TcpClient(new IPEndPoint("10.10.0.100", 50010));
        TCPSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        LingerOption lo = new LingerOption(true, 0);
        TCPSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);

        TCPSocket.Connect(new IPEndPoint("10.10.0.50", 50010));
        TCPSocket.ReceiveTimeout = 5000;
        
        //Do somthing

       TCPSocket.Client.Shutdown(SocketShutdown.Both);
       TCPSocket.Close();
       Thread.Sleep(5000);

       TCPSocket.Connect(new IPEndPoint(SRE3021IP, SRE3021TCPPort)); //ExtendedSocketExeption 
 

И я проверяю cmd с помощью команды netstat -ano | findstr 50010 , пока поток спал.

   TCP    10.10.0.100:50010      10.10.0.50:50010       TIME_WAIT       0
 

Состояние TIME_WAIT оставалось около 30~1 минуты, затем Оно исчезло…

Я не знаю, почему опция linger не была применена.

Ответ №1:

Установка параметра LingerOption не останавливает закрытие сокета. Это задерживает close (), чтобы разрешить отправку любых неотправленных данных в буфере. Это позволяет приложению перейти к следующему этапу работы с медленной сетью. Розетка все равно закроется.

ReuseAddress не имеет ничего общего с повторным использованием существующего сокета (хотите верьте, хотите нет), он позволяет прослушивающему сокету привязываться к существующему порту прослушивания. Это очень индивидуальное поведение, и для взаимодействия с другими процессами требуется, чтобы два разных приложения прослушивали один и тот же порт. Этот параметр не имеет полезного значения для исходящего сокетного соединения.

Ваша проблема связана с тем, что вы устанавливаете привязку источника к этой строке:

TCPSocket = new TcpClient(new IPEndPoint("10.10.0.100", 50010 ));

Если вы хотите установить исходный порт, у вас нет другого выбора, кроме как ждать, пока ОС очистит сокет из списка подключений, что означает ожидание истечения срока действия TIME_WAIT.

Если вы не хотите устанавливать исходный порт (а в наши дни очень мало причин для того, чтобы на самом деле устанавливать исходный порт), но все же хотите выбрать конкретный интерфейс IP-адреса источника, вы можете использовать:

TCPSocket = new TcpClient(new IPEndPoint("10.10.0.100", 0));

Если вы хотите, чтобы Windows просто выбрала наиболее подходящий исходящий интерфейс (и порт), затем используйте:

TCPSocket = new TcpClient();

Комментарии:

1. Спасибо за ваш любезный ответ. Я меняю TCPSocket = новый TcpClient, и это решает проблему!