2009-03-24 1 views
3

Надеюсь, кто-то может нам помочь, поскольку мы добираемся до расследований!TCP Socket Server генерирует CLOSE_WAITs Время от времени до неоперабельного

У нас есть простой асинхронный сервер сокетов, написанный на C#, который принимает подключения из веб-приложения ASP.NET, отправляет сообщение, выполняет некоторую обработку (как правило, и с БД, но с другими системами), а затем отправляет ответ назад к клиенту. Клиент отвечает за закрытие соединения.

У нас возникли проблемы, если система находится под большой нагрузкой в ​​течение длительного периода времени (обычно дни), на ядре сервера (netstat -a) формируются сокеты CLOSE_WAIT до такой степени, что процесс не будет принимать любые дальнейшие соединения. В этот момент мы должны отскочить процесс, и он снова запускается.

Мы попытались выполнить некоторые тесты нагрузки нашего приложения ASP.NET, чтобы попытаться реплицировать проблему (поскольку вывести некоторую проблему из кода было невозможно). Мы считаем, что нам удалось это и в конечном итоге с WireShark packet trace вопроса проявляется как SocketException в журналах сокет сервера:

System.Net.Sockets.SocketException: Существующее соединение было принудительно закрыто удаленный хост на System.Net.Sockets.Socket.BeginSend (байт [] буфера, Int32 смещение, Int32 размер, SocketFlags SocketFlags, AsyncCallback обратного вызова, состояние объекта)

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

Есть ли у кого-нибудь какие-либо предложения о следующих вещах, чтобы попытаться, проверить или увидеть очевидные вещи, которые мы можем делать неправильно?

ответ

5

Посмотрите на диаграмме

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

Вашего клиент закрыл соединение, вызывая близко(), который послал FIN на сервере сокет, который ACKed плавника и состояние которых в настоящее время изменено на CLOSE_WAIT и остается таким образом, если сервер не выдает запрос close() на этот сокет.

Ваша программа сервера должна определить, прекратил ли клиент прерывание соединения, а затем немедленно закрыть(), чтобы освободить порт. Как? Обратитесь к разделу read(). После чтения конца файла (что означает FIN), возвращается ноль.

3

Клиент отвечает за закрытие соединения.

Как клиент, так и сервер должны закрыть и выключить сокет. Либо клиент не заканчивает закрытие (маловероятно - так как он будет запускать финализатор), либо сервер не отключит сокет (скорее всего).

using (Socket s = new Socket(/* */)) { 
    /* Do stuff */ 
    s.Shutdown(SocketShutdown.Both); 
    s.Close(); 
} 
+0

На стороне клиента сокет закрывается как часть блока использования (..), но мы в это время не делаем. Шаттл и. Закрываем явно - что не является проблемой при нормальном тестировании. Сервер явно выполняет оба пути ко всем путям кода, которые мы можем найти (сложный, потому что он асинхронный). –

+0

@Kieran - факт, что отскакивание серверного процесса очищает CLOSE_WAIT, указывает, что вы не закрываете где-то, я думаю. –

-2

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

EDIT - это должно быть TIME_WAIT, а не CLOSE_WAIT выше.

+0

Они могут зависнуть намного дольше, чем если бы по какой-то причине соединение заклинило, см .: http://blog.zhuzhaoyuan.com/2009/03/a-word-on-time_wait-and-close_wait/. Это не такая естественная вещь, как TIME_WAIT. –

+0

Я получаю close_wait и time_wait смущен или что-то в этом роде? – Chris

+1

Вы думаете о TIME_WAIT Крисе. –

0

Вы не должны оставлять ответственность за закрытие сокетов TCP только до клиента. Что произойдет, если клиентский процесс/машина выйдет из строя?

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

5

Если ваш сервер накапливает сокеты CLOSE_WAIT, то он не закрывает свой сокет, когда соединение завершено. Если вы посмотрите на диаграмму состояния в комментарии к сообщению Криса, вы увидите, что CLOSE_WAIT переходит на LAST_ACK после того, как сокет закрыт и отправлен FIN.

Вы говорите, что сложно определить, где это сделать из-за асинхронной природы? Это не должно быть проблемой, вы должны закрыть сокет, если обратный вызов из вашего recv возвращает 0 байтов (если вам нечего делать, когда клиент закрывает свою сторону соединения). Если вам действительно нужно беспокоиться о продолжении отправки, сделайте здесь Shutdown (recv) и обратите внимание, что ваш клиент закрылся, как только вы закончите отправку, выполните Shutdown (отправить) и Close.

ВЫ МОЖЕТЕ выдавать новое чтение в обратном вызове из чтения, которое возвращает 0, указывающее, что клиент закрыт, и это может вызвать проблемы?

0

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

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

Простыми словами, когда сервер снова выдает команду чтения (listener.read() или listener.beginread (...) в режиме async), чтение вернет 0 байтов, это само по себе указывает на то, что сокет должен быть закрыт слушателем, так как любые другие операции в сокете перестали выполняться клиентом.