Winsock tcp / ip Socket прослушивает, но соединение отказано, состояние гонки? - PullRequest
2 голосов
/ 25 апреля 2010

Это включает в себя два автоматизированных модульных теста, каждый из которых запускает tcp / ip-сервер, который создает неблокирующий сокет, затем bind () s и listen () в цикле на select () для клиента, который подключается и загружает некоторые данные.

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

UNLESS

между ними существует Thread.Sleep () из нескольких секунд ?? !!!

Интересно, что повторяющийся цикл повторяется каждую 1 секунду для подключения после любого сбоя. Таким образом, второй тест проходит некоторое время до истечения времени ожидания через 10 минут.

В течение этого времени netstat -na показывает, что правильный номер порта находится в состоянии LISTEN для сокета сервера. Так что, если он находится в состоянии прослушивания? Почему он не принимает соединение?

В коде есть сообщения журнала, которые показывают, что select НИКОГДА даже не получает готовый к считыванию сокет (что означает готовность принимать соединение, когда оно применяется к прослушивающему сокету).

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

Это не было бы так плохо, если бы логика повторения позволила ему соединиться через пару секунд. Однако, похоже, что он «застрял» и даже не попытается.

Однако по какой-то странной причине прослушивающий сокет говорит, что находится в состоянии LISTEN, даже несмотря на то, что продолжает отказывать в соединениях.

Таким образом, это означает, что это операционная система Windoze, которая на самом деле перехватывает пакет SYN и возвращает пакет RST (что означает «Соединение отказано»).

Единственный раз, когда я видел эту ошибку, это когда в коде была проблема, из-за которой сотни сокетов застревали в состоянии TIME_WAIT. Но это не тот случай. netstat показывает только около дюжины сокетов с только 1 или 2 в TIME_WAIT в любой данный момент.

Пожалуйста, помогите.

Ответы [ 3 ]

2 голосов
/ 25 апреля 2010

Я провел множество подобных тестов на сборочных машинах с различными операционными системами Windows (от XP до Windows 7) с различным количеством ядер, и я никогда не видел, чтобы это было проблемой.

Я не верю, что переход на прослушивающий сокет в TIME_WAIT может быть вашей проблемой; Я, конечно, никогда этого не видел, и я регулярно запускаю тесты клиент-сервер с одним и тем же портом, где я запускаю и останавливаю серверы в течение периода задержки TIME_WAIT.

Если вы запускаете свой второй сервер до того, как ваш первый закроет сокет (или, если сокет был в TIME_WAIT), то я ожидаю, что ваш второй сервер получит ошибку при попытке bind().) .

Лично я думаю, что более вероятно, что в вашем коде есть проблема, которая принимает подключения - то есть ваш тест мог найти ошибку;)

Можем ли мы взглянуть на код между вашим прослушиванием и циклом принятия?

Есть ли у вас проблемы, если вы измените порядок тестов?

Клиент и сервер работают на одной и той же машине, меняет ли это вещи, если они не работают?

1019 * Etc. *

У меня есть некоторые инструменты тестирования TCP http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html,, если вы настроили свою тестовую систему для запуска тестового клиента с этой ссылки на пример сервера с этого http://www.lenholgate.com/blog/2005/11/simple-echo-servers.html, вы все еще видите свою проблему? (То есть, запустите мой сервер с моим клиентом в вашей тестовой системе, чтобы он запускал его так же, как он запускает ваши вещи и работает ли мой материал?).

2 голосов
/ 24 мая 2010

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

Эта логика была заменена для более интеллектуального чтения любых данных и правильного закрытия, когда чтение возвращает 0. Таким образом, оно закрылось гораздо быстрее.

Так что оказалось неправильным закрытие сокета в моем собственном коде.

Спасибо за помощь!

1 голос
/ 25 апреля 2010

С Этот сайт MSDN :

Состояние TIME_WAIT определяет время, которое должно пройти, прежде чем TCP сможет освободить закрытое соединение и повторно использовать свои ресурсы. Этот интервал между закрытием и освобождением известен как состояние TIME_WAIT или состояние 2MSL. В течение этого времени соединение может быть восстановлено с гораздо меньшими затратами для клиента и сервера, чем установление нового соединения. Поведение TIME_WAIT определено в RFC 793, который требует, чтобы TCP поддерживал закрытое соединение в течение интервала, по крайней мере равного удвоенному максимальному времени жизни сегмента (MSL) сети. Когда соединение освобождается, его пара сокетов и внутренние ресурсы, используемые для сокета, могут использоваться для поддержки другого соединения.

Windows TCP возвращается в состояние TIME_WAIT после закрытия соединения. Находясь в состоянии TIME_WAIT, пара сокетов не может быть повторно использована. Период TIME_WAIT настраивается путем изменения следующего параметра реестра DWORD, который представляет период TIME_WAIT в секундах.

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters\TcpTimedWaitDelay

По умолчанию значение MSL составляет 120 секунд. Параметр реестра TcpTimedWaitDelay по умолчанию имеет значение 240 секунд, что в 2 раза превышает максимальное время жизни сегмента, равное 120 секундам или 4 минутам. Однако вы можете использовать эту запись для настройки интервала. Уменьшение значения этой записи позволяет TCP быстрее освобождать закрытые соединения, предоставляя больше ресурсов для новых соединений. Однако если значение слишком низкое, TCP может освободить ресурсы подключения до завершения подключения, что потребует от сервера использования дополнительных ресурсов для восстановления подключения. Этот параметр реестра может быть установлен от 0 до 300 секунд.

Я думаю, что минимальное значение, которое вы можете установить - 30 (попробуйте меньше, но оно может не работать)

Более подробное объяснение см. В FAQ программиста Winsock .

...