#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, и это решает проблему!