Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Лимиты Сокета


Автор: nerdy_weirdie 10.11.2008, 20:24
Добрый вечер. У меня возникла проблема с серверным приложением. Может, кто сталкивался.
Программа принимает подключения от клиентов (accept();) и в потоке работает с ними, завершая работу shutdown()+closesocket(). Основную часть времени соединения находятся в режиме ожидания - нагрузка на канал небольшая. Соединений обычно около 2к.
Проблема в следующем: примерно раз в сутки мне приходится рестартовать программу, потому что она перестает принимать подключения, причем на любой открытый сокет, а не только на тот, что принимает основную часть подключений. Клиент получает ошибку "удаленный хост принудительно разорвал соединение". Другие программы при этом сохраняют способность принимать подключения.
Такое ощущение, что есть какие-то лимиты у winsocket.
Проверил ветку реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters - там нет параметра TcpNumConnections, видимо, не ограничен.
В чем может быть дело?

Автор: SVN74 10.11.2008, 21:07
А в потоке по работе с клиентом при ошибке соединения сокет закрывается (closesocket) ?

Автор: J0ker 10.11.2008, 22:31
http://forum.vingrad.ru/index.php?showtopic=233713&view=findpost&p=1680133
сокеты надо правильно закрывать потомучто

Добавлено через 2 минуты и 25 секунд
в winsock есть лимиты на полуоткрытые сокеты, но это относится к исходящим соединениям

Автор: nerdy_weirdie 12.11.2008, 21:50
Цитата(J0ker @ 10.11.2008,  22:31)
http://forum.vingrad.ru/index.php?showtopic=233713&view=findpost&p=1680133
сокеты надо правильно закрывать потомучто

Добавлено @ 22:33
в winsock есть лимиты на полуоткрытые сокеты, но это относится к исходящим соединениям

При завершении сеанса работы с клиентом, сервер всегда заканчивает связь вызовами  shutdown()+closesocket(). Этого не достаточно?

Автор: J0ker 13.11.2008, 21:22
проверьте netstat'ом на наличие большого числа сокетов в состояние FIN_WAIT
так-же я не уверен, как у вас обстоит дело со слушающим сокетом - вы его живым держите или после каждого accept'а ребайндаете?

Добавлено через 14 минут и 41 секунду
да, и на будущее
правильная последовательность закрытия TCP соединения:
инициатор - инициатор завершения соединения
Код

инициатор                          peer
-----------------------------------------------------------------------
shutdown(SD_SEND)          --->    recv пакет длиной 0
recv оставшихся данных*    <---    send оставшихся данных (опционально)
recv пакета длиной 0*      <---    shutdown(SD_BOTH)
shutdown(SD_RECV)                  closesocket()
closesecket()

(*) - должны применяться таймауты - в случае истечения таймаута выполняется переход к shutdown(SD_RECV) 

Автор: nerdy_weirdie 13.11.2008, 23:24
в цикле только accept() + ::CloseHandle(::CreateThread()).
Вот, наблюдаю за нетстатом - пока что только исключительно "ESTABLISHED".

Автор: J0ker 14.11.2008, 00:49
вы не должны вызывать CreateThread
если вы работаете с MFC - используйте AfxBeginThread
для остального - _beginthread
CreateThread можно использовать только в raw windows API
в этом возможно как раз и проблема

Автор: nerdy_weirdie 30.11.2008, 07:40
Цитата(J0ker @ 14.11.2008,  00:49)
вы не должны вызывать CreateThread
если вы работаете с MFC - используйте AfxBeginThread
для остального - _beginthread
CreateThread можно использовать только в raw windows API
в этом возможно как раз и проблема

Не, MFC не использую.
Спасибо за ответ, но мне кажется что в этом врядли может скрываться причина. Будь то AfxBeginThread или _beginthread, все они вызывают ::CreateThread.

Добавлено через 11 минут и 15 секунд
Цитата(J0ker @ 13.11.2008,  21:22)
проверьте netstat'ом на наличие большого числа сокетов в состояние FIN_WAIT
так-же я не уверен, как у вас обстоит дело со слушающим сокетом - вы его живым держите или после каждого accept'а ребайндаете?

Добавлено @ 21:37
да, и на будущее
правильная последовательность закрытия TCP соединения:
инициатор - инициатор завершения соединения
Код

инициатор                          peer
-----------------------------------------------------------------------
shutdown(SD_SEND)          --->    recv пакет длиной 0
recv оставшихся данных*    <---    send оставшихся данных (опционально)
recv пакета длиной 0*      <---    shutdown(SD_BOTH)
shutdown(SD_RECV)                  closesocket()
closesecket()

(*) - должны применяться таймауты - в случае истечения таймаута выполняется переход к shutdown(SD_RECV)

Дело в том что, как показывает статистика, основная причина завершения соединения - разрыв подключения к интернету у клиента. Чем это чревато? Незакрытые сокеты видимо не висят, т.к. потоков в момент коллапса наблюдается не больше обычного. Такие ситуации требуют особой обработки сервером? Возможно, в этом и кроется моя проблема. 

Автор: MAKCim 30.11.2008, 11:29
Цитата(J0ker @  13.11.2008,  21:22 Найти цитируемый пост)
проверьте netstat'ом на наличие большого числа сокетов в состояние FIN_WAIT

нет такого состояния  smile

Добавлено через 5 минут и 2 секунды
Цитата(nerdy_weirdie @  30.11.2008,  07:40 Найти цитируемый пост)
разрыв подключения к интернету у клиента.

как именно разрыв происходит?

посмотри, в каком состоянии находятся сокеты на стороне сервера
сразу станет понятно

Автор: Олег2005 30.11.2008, 14:30
Цитата(nerdy_weirdie @  10.11.2008,  19:24 Найти цитируемый пост)
TcpNumConnections, видимо, не ограничен.

Какая ОС?
Цитата
Windows XP для повышения безопасности введен новый механизм, ограничивающий число одновременных попыток подключений каждого процесса десятью в секунду (но не ограничивающий вообще число установленных одновременных подключений!), что призвано снизить вредоносный эффект от некоторых типов вирусов. Если же опасность новых вирусных эпидемий вас волнует мало, а главное для вас - скорость, то придется пропатчить системный файл TCPIP.SYS (параметр TcpNumConnections реестра не сработает!).


Цитата(nerdy_weirdie @  10.11.2008,  19:24 Найти цитируемый пост)
Проблема в следующем: примерно раз в сутки мне приходится рестартовать программу, потому что она перестает принимать подключения, причем на любой открытый сокет, а не только на тот, что принимает основную часть подключений. Клиент получает ошибку "удаленный хост принудительно разорвал соединение". Другие программы при этом сохраняют способность принимать подключения.

Проблема описана некорректно.
Что значит - принимать подключения?
Подключения принимаются только на слушающий сокет - параметр длины очереди устанавливается в listen()
А поэтому фраза:"перестает принимать подключения, причем на любой открытый сокет, а не только на тот, что принимает основную часть подключений." - абсолютно непонятна.
На любой сокет принимать подключения - нельзя - прием идет только по одному - слушающему.
А запросы обслуживаются на акцептированных (присоединенных) сокетах.
Так что сформулируйте проблему покорректнее


Автор: nerdy_weirdie 30.11.2008, 15:12
Олег2005, да, я имел ввиду слушающие сокеты, listen()+<accept() в цикле>.
ОС Windows Server 2003, но всё равно об этом патче TCPIP.SYS почитаю, спасибо.

Добавлено через 9 минут и 47 секунд
Длина очереди в listen() установлена в SOMAXCONN.

Автор: nerdy_weirdie 30.11.2008, 15:40
Цитата(MAKCim @ 30.11.2008,  11:29)
Цитата(nerdy_weirdie @  30.11.2008,  07:40 Найти цитируемый пост)
разрыв подключения к интернету у клиента.

как именно разрыв происходит?

посмотри, в каком состоянии находятся сокеты на стороне сервера
сразу станет понятно

При нештатном уходе клиента из онлайна сервер замечает это по send() == -1,
::GetLastError() == 10054 An existing connection was forcibly closed by the remote host. 

Обрабатывает он эту ситуацию:
shutdown(s,SD_BOTH);
closesocket(s);
Собственно, сокеты незакрытые, видимо, не висят.

Автор: Олег2005 30.11.2008, 15:47
Цитата(nerdy_weirdie @  30.11.2008,  14:12 Найти цитируемый пост)
SOMAXCONN. 

И сколько же стоит?

Добавлено @ 15:49
Цитата(nerdy_weirdie @  30.11.2008,  14:40 Найти цитируемый пост)
При нештатном уходе клиента из онлайна сервер замечает это по send() == -1,
::GetLastError() == 10054 An existing connection was forcibly closed by the remote host. 

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

Автор: J0ker 30.11.2008, 19:27
Цитата(nerdy_weirdie @  30.11.2008,  07:40 Найти цитируемый пост)
Спасибо за ответ, но мне кажется что в этом врядли может скрываться причина. Будь то AfxBeginThread или _beginthread, все они вызывают ::CreateThread.

только они еще и инициализируют библиотеки в потоках - _beginthread - CRT, а AfxBeginThread - CRT и afx
я вам совершенно серьезно советую исправить - вероятность что именно здесь собака и порылась очень высока


Цитата(MAKCim @  30.11.2008,  11:29 Найти цитируемый пост)
нет такого состояния

есть
после отсылки пакета с выставленым FIN сокет переходит в состояние FIN_WAIT_1, а после приема ACK без FINа переходит в состояние FIN_WAIT_2
правда я не уверен, что netstat эти состояния отображает - не задавался таким вопросом

nerdy_weirdie, совершенно серьезно - обрати внимание на ::CreateThread - при отсутствии инициализации библиотек в потоке могут быть точно такие явления как ты описал

Автор: Олег2005 30.11.2008, 21:31
Есть еще вариант - на каждый поток выделяется память - 1 мег в раме.
Как с этим делом?

Автор: MAKCim 30.11.2008, 22:27
Цитата(J0ker @  30.11.2008,  19:27 Найти цитируемый пост)
есть
после отсылки пакета с выставленым FIN сокет переходит в состояние FIN_WAIT_1, а после приема ACK без FINа переходит в состояние FIN_WAIT_2

верно
и где здесь FIN_WAIT?  smile 

Автор: nerdy_weirdie 30.11.2008, 23:50
Видимо, таки где-то есть утечка хендлов. Вот, таскменеджером наблюдаю.
Сразу после запуска их было примерно по 5 на поток.
Через несколько часов около 10 на поток.
И сейчас, часов через 8 стало около 12 на поток. Только ума пока что не приложу, откуда они утекают.
Может, кто знает какой попроще способ узнать, откуда лишние хендлы при 2000 работающих потоках ))

Автор: J0ker 1.12.2008, 01:17
Цитата(MAKCim @ 30.11.2008,  22:27)
Цитата(J0ker @  30.11.2008,  19:27 Найти цитируемый пост)
есть
после отсылки пакета с выставленым FIN сокет переходит в состояние FIN_WAIT_1, а после приема ACK без FINа переходит в состояние FIN_WAIT_2

верно
и где здесь FIN_WAIT?  smile

имелось ввиду в каком-либо FIN_WAIT - _1 или _2
ну впрочем тебя я не осуждаю - сие очевидно только ОО программистам  smile

Добавлено через 5 минут и 4 секунды
Цитата(nerdy_weirdie @  30.11.2008,  23:50 Найти цитируемый пост)
Только ума пока что не приложу, откуда они утекают.

вы игнорируете мое предупреждение насчет CreateThread
CRT и MFC имеют глобальные объекты, которые должны быть инициализированны на каждый поток отдельно - при отсутствии инициализации последствия непредсказуемы и трудно обнаруживаемы
в том числе это может быть и утечка ресурсов

Автор: MAKCim 1.12.2008, 02:21
Цитата(J0ker @  1.12.2008,  01:17 Найти цитируемый пост)
ну впрочем тебя я не осуждаю - сие очевидно только ОО программистам 

ага, и потом вот из-за таких ОО программистов и ракеты взрываются, и еще куча всего нехорошего происходит  smile 
очевидно != формально

Автор: J0ker 1.12.2008, 03:38
Цитата(MAKCim @ 1.12.2008,  02:21)
Цитата(J0ker @  1.12.2008,  01:17 Найти цитируемый пост)
ну впрочем тебя я не осуждаю - сие очевидно только ОО программистам 

ага, и потом вот из-за таких ОО программистов и ракеты взрываются, и еще куча всего нехорошего происходит  smile 
очевидно != формально

из-за формалистов происходит столько всяких неприятностей, что одной ракетой больше, одной меньше - никакого рояля не играет  smile 

Автор: MiklVolkov 4.7.2009, 07:40
Уважаемые, если проблему решили, то подскажите как?
Я наступил н теже грабли.

Есть набор клиент-серверных приложений собственной разработки. Для связи используются сокеты в виде  классов в которых реализовна и клиентская и серверная части. Вся часть ПО ответственная за связь вынесена в отдельную DLL.

Сервер запускается, клиенты к нему подключаются, отключаются и т.д. и т.п.
Все нормально работало неделями - дольше не получалось тестировать непрерывно - приходилось перезапускать.
Клиентов было штук 20.

Сейчас клиентов увеличил до 150. Теперь все работает но 2,5 дня. Может и дольше - до недели, но не меньше точно.
Потом происходит следующая ситуация. Сервер видит подключения клиентов, новые подключаются, старые отключаются, но данные не пересылаются ни в одну сторону.

Была идея - сделать перезапуск класса сервера, отвечающего за связь. Обнаружил интересную штуку - если сделать этот перезапуск искусственно - скажем через 1 сутки - все нормально работает. Но если дождаться когда связь "отвалится" сама - увы, клиенты подключаются, а данные не ходят ни в одну сторону.

Перезапускаешь приложение - все опять работает.
Понятно, что где-то что-то переполняется, но вот что и где?

Да, еще забыл добавить интересное наблюдение - перезапуск класса связи искусственно срабатывает 101 раз. А потом надо один фиг перезагружать всю программу целиком.

Памяти сколько выделено и нитей - столько же, сколько и при старте программы.
А вот насчет netstat - сказать ничего не могу - я только что про нее узнал
Средствами VS никаких утечек чего либо не обнаруживается.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)