2013-07-12 3 views
0

ОБНОВЛЕНИЕ: После исследования lil больше я нашел реальную проблему для этого поведения. Проблема в том, что я создаю потоки для каждого соединения и передаю носок fd в поток, но не сразу pthraed_joining, так что мой основной поток не смог создать больше потоков после принятия соединения. и моя логика закрытия сокета в дочернем потоке, потому что я не смог закрыть сокет и, следовательно, они собирались в состояние WAIT CLOSE. Я просто отделил потоки после их создания, и все работает хорошо!Розетки не закрываются после 32739 соединений

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

netstat -tonpa 2>&1 | grep CLOSE 

Я вижу около 1020 сокетов, ожидающих ЗАКРЫТЬ. образец из команды,

tcp 25 0 192.168.0.175:16099 192.168.0.175:41704 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0) 
tcp 24 0 192.168.0.175:16099 192.168.0.175:41585 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0) 
tcp 30 0 192.168.0.175:16099 192.168.0.175:41679 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0) 
tcp 31 0 192.168.0.175:16099 192.168.0.175:41339 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0) 
tcp 25 0 192.168.0.175:16099 192.168.0.175:41760 CLOSE_WAIT 5250/./bl_manager off (0.00/0/0) 

Я использую следующий код, чтобы обнаружить отключение клиента.

for(fd = 0; fd <= fd_max; fd++) { 
    if(FD_ISSET(fd, &testfds)) { 
     if (fd == client_fd) { 
      ioctl(fd, FIONREAD, &nread); 
      if(nread == 0) { 
       FD_CLR(fd, &readfds); 
       close(fd); 
       return 0; 
      } 
     } 
    } 
} /* for()*/ 

Пожалуйста, дайте мне знать, если что-то не так. Это настройка клиента Python и CPP.

спасибо

+0

На какой платформе вы работаете? Кроме того, почему этот помеченный Python? У вас есть основания полагать, что клиент делает что-то своеобразное с сокетами, которые препятствуют работе вашего сервера? – abarnert

+0

Да, я сомневался в этом! – bana

ответ

2

CLOSE-WAIT означает, что порт ожидает локальное приложение, чтобы закрыть сокет, уже получил близко от сверстников. Очевидно, что вы как-то утечка сокетов, возможно, в пути ошибок.

Ваш код, чтобы «обнаружить отключение клиента» является полностью неправильным. Все, что вы тестируете, - это количество данных, которые можно читать без блокировки, то есть уже достигнутые. Правильный тест - это возвращаемое значение из recv() или ошибка, отличная от EAGAIN/EWOULDBLOCK при чтении или записи.

+0

Разве это не означает, что ioctl используется, чтобы видеть, есть ли какие-либо данные в сокете для чтения или нет, без фактического чтения. Поскольку я знаю, что он возвращает 0, если сокет закрыт с другой стороны, пожалуйста, дайте мне знать, если мое понимание ошибочно. – bana

+0

Ваше «понимание» неверно, действительно беспочвенное. Прочитайте то, что я написал снова, или просмотрите документацию FIONREAD: «возвращает количество байтов, которые сразу доступны для чтения», «возвращает количество байтов во входном буфере» и т. Д. И т. Д. Ни слова о сверстке не отключается нигде , – EJP

+0

http://stackoverflow.com/questions/283375/detecting-tcp-client-disconnect Если это не так, мы должны обязательно сообщить этим парням о вышеуказанной теме. Но для меня он работает нормально, как и ожидалось! он обнаруживает соединение ближе клиентом. – bana

1

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

fd_set представляет собой набор битов, индексированных по номерам дескрипторов файлов. Каждая платформа имеет разное максимальное количество. OpenBSD и последние версии FreeBSD и OS X, как правило, ограничивают fd_set к FD_SETSIZE, который по умолчанию 1024. Различные Линукс коробки, кажется, 1024, 4096, 32768 и 65536.

Итак, что произойдет, если вы FD_ISSET(32800, &testfds) и FD_SETSIZE 32768 ? Вы просите его прочитать немного из произвольной памяти.

select или другой вызов перед этим должны дать вам ошибку EINVAL при передаче в 32800 для параметра nfds ... но исторически, многие платформы еще не сделали этого. Или они вернули ошибку, но только после правильного заполнения первых FD_SETSIZE битов и оставления остального набора в неинициализированной памяти, а это означает, что если вы забыли проверить ошибку, ваш код, похоже, работает до тех пор, пока вы не подчеркнете его.

Это одна из причин использования select для более чем нескольких сотен сокетов - это плохая идея. Другая причина заключается в том, что select является линейным (и, что еще хуже, не линейным по числу текущих сокетов, но линейных на наивысшем fd, поэтому даже после того, как большинство клиентов уходит, оно все еще медленное).

Большинство современных платформ, имеющих select, также имеют poll, что позволяет избежать этой проблемы.

Если вы не на Windows ... в этом случае есть полностью разные причины не использовать select и разные ответы.

+0

Большое спасибо за ответ! после изучения немного больше я нашел причину быть другой для моей проблемы. Я полностью понимаю, что вы сказали, и я тоже думал об этом. Но дело в том, что эти потоки настолько коротки, что в миллисекундах они закрывают сокет и умирают. поэтому сокет fd повторно используется. Как я думаю, я нашел решение своей проблемы, я попытаюсь обновить вопрос! – bana

Смежные вопросы