После того, как я получил более глубокое понимание этой темы, я могу дать ответ сам себе.
Всякий раз, когда вы открываете и закрываете сокет, он переходит в состояние «ВРЕМЯ ОЖИДАНИЯ», прежде чем полностью закрыться. Это состояние должно препятствовать тому, чтобы следующее tcp-соединение получало задержанные tcp-пакеты позже.
Я имел дело с приложением, которое отправляет несколько тысяч CGI-запросов на сервер. Проблема заключалась в том, что сервер использовал HTTP / 1.0, что означает, что каждый запрос открывает новый сокет и закрывает его сразу после обмена данными.
Через некоторое время тысячи соединений tcp показываются в netstat в состоянии «ВРЕМЯ ОЖИДАНИЯ». Разъемы, или, если быть более точными, порты стали исчерпаны. Windows не предоставляла приложению новые сокеты для новых запросов CGI. Через некоторое время все сокеты TIME-WAIT были закрыты, и приложение могло продолжить связь. Эта проблема возникла из-за природы сервера HTTP / 1.0.
Существует два «исправления» этой проблемы с точки зрения Windows. Изменяя REGISTRY, вы можете позволить Windows управлять более чем 5000 соединений по умолчанию (я прочитал хороший верхний предел, который может быть 20.000). Другой вариант - уменьшить время ожидания. Это также может быть сделано путем настройки реестра. Оба варианта не были реальным решением нашей огромной проблемы с истощением сокетов.
В конечном решении мы использовали опцию сокета TCP под названием «SO-LINGER». Установка этой опции при создании порта позволяет пропустить состояние TIME-WAIT сокета TCP.
Пожалуйста, имейте в виду, что это состояние существует по причине! Пропуск этого был одним из последних вариантов и соответствует нашим потребностям, потому что мы передаем пару байтов через сокет. Перед использованием этой опции рассмотрите возможные воздействия.
Проект разработан в VB .NET 4.0. Код, который я использовал для создания сокета, размещен ниже:
Private _plcAddress As String
Private _plcSocket As Socket
Private _endPoint As IPEndPoint
...
Dim myOpts As New LingerOption(True, 0)
Dim ipAddress As IPAddress = ipAddress.Parse(plcAddress)
_plcAddress = plcAddress
_plcSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP)
_plcSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, myOpts)
_endPoint = New IPEndPoint(IPAddress, 80)
...