Сокет все еще прослушивается после сбоя приложения

У меня возникла проблема с одним из моих приложений на C++ в Windows 2008x64 (это же приложение отлично работает в Windows 2003x64).

После сбоя или даже иногда после обычного цикла выключения / перезапуска у него возникает проблема с использованием сокета на порту 82, которому необходимо получать команды.

Глядя на netstat, я вижу, что сокет все еще находится в состоянии прослушивания более 10 минут после остановки приложения (процесс определенно больше не работает).

  TCP    0.0.0.0:82             LISTENING

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

int doReuse = 1;
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR,
           (const char *)&doReuse, sizeof(doReuse)); 

Любые идеи, что я могу сделать, чтобы решить или, по крайней мере, избежать этой проблемы?

ИЗМЕНИТЬ:

Сделал netstat -an, но это все, что я получаю:

  TCP    0.0.0.0:82             0.0.0.0:0              LISTENING

Для netstat -anb я получаю:

  TCP    0.0.0.0:82             0.0.0.0:0              LISTENING
 [System]

Я знаю о корректном закрытии, но даже если приложение по какой-то причине выйдет из строя, мне все равно нужно иметь возможность перезапустить его. Рассматриваемое приложение использует внутреннюю библиотеку, которая внутренне использует Windows Sockets API.

ИЗМЕНИТЬ:

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


person BrokenGlass    schedule 16.12.2010    source источник
comment
Если у вас возникли проблемы даже после перезагрузки компьютера, это может быть какая-то другая программа, использующая ваш порт. Сделайте netstat -anb, чтобы узнать, кто слушает на 82.   -  person Eugen Constantin Dinca    schedule 16.12.2010
comment
Это нормально после аварии. Информация о сокетах хранится в ОС (ваше приложение просто содержит дескриптор информации). Когда ваше приложение дает сбой (или закрывается без закрытия соединения), сокет будет оставаться в использовании до тех пор, пока ОС не обнаружит, что слушающее приложение исчезло (иногда это может быть добрых 10 минут). Лучше всего передать порт в качестве аргумента командной строки, чтобы вы могли быстро изменить порт во время отладки.   -  person Martin York    schedule 17.12.2010
comment
У вас есть какое-либо сообщение об ошибке в журнале событий Windows? Возможно, Event-ID 4227?.   -  person Luis G. Costantini R.    schedule 17.12.2010
comment
@Martin: Проблема в том, что состояние сокета остается в состоянии Listening навсегда, даже через несколько часов я не могу успешно перезапустить приложение. Я также не могу изменить порт, так как другие приложения отправляют команды на фиксированный порт (82). Нет ли способа повторно использовать сокет? Это же приложение отлично работало на Win 2003.   -  person BrokenGlass    schedule 17.12.2010
comment
Это проблема при разработке программного обеспечения. Решение, которое я использую (когда я не могу изменить сокет). Я запускаю прокси (который работает и не дает сбоев), который прослушивает этот сокет и перенаправляет любые входящие данные на 82 на настраиваемый порт. Затем вы можете написать свое экспериментальное программное обеспечение, чтобы использовать другой порт каждый раз, когда вам нужно переключить порт. Вызывающему приложению не нужно знать, что ваше приложение переместилось на другой порт, поскольку это делается путем перенастройки прокси-сервера.   -  person Martin York    schedule 17.12.2010
comment
К вашему сведению: вы можете использовать готовую часть программного обеспечения для прокси-сервера, предложенного Мартином Йорком, если вы можете найти порт netpipes (purplefrog.com/~thoth) для Windows.   -  person JimR    schedule 18.12.2010


Ответы (6)


Если это мешает вам только во время отладки, используйте tcpview от разработчиков sysinternals, чтобы принудительно закрыть сокет. Я предполагаю, что это работает на вашей платформе, но я не уверен.

Если вы выполняете операции блокировки на любых сокетах, не используйте неопределенный тайм-аут. По моему опыту, это может вызвать странное поведение на многопроцессорной машине. Я не уверен, что это была за серверная ОС Windows, но это была одна или две версии до 2003 Server. Вместо неопределенного времени ожидания используйте время ожидания от 30 до 60 секунд, а затем просто повторите ожидание. Это также относится к перекрывающимся портам ввода-вывода и ввода-вывода, если вы их используете.

Если это приложение, которое вы отправляете для использования другими, удачи. Windows может быть чистым ублюдком при использовании сокетов...

person JimR    schedule 17.12.2010
comment
Я смог использовать tcpview, чтобы закрыть подключенный сокет для несуществующего процесса, но не прослушивающий сокет. - person Gabe; 17.04.2015

Я попытался установить для параметра сокета значение REUSEADDR, но, насколько мне известно, это влияет только на повторное подключение к порту, находящемуся в состоянии TIME_WAIT.

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

person user207421    schedule 17.12.2010
comment
на самом деле система никогда не восстанавливается, даже по прошествии нескольких часов порт становится непригодным для использования, в основном только перезагрузка устраняет проблему в этот момент - этого не было в случае с Win 2003x64, поэтому что-то в этом отношении должно было измениться с Win 2008. - person BrokenGlass; 17.12.2010
comment
Тогда это баг ОС. Сообщите об этом в Microsoft. - person user207421; 17.12.2010

Первое, что нужно проверить, это то, что это действительно ваше приложение прослушивает этот порт. Использовать:

netstat -anb

чтобы выяснить, какой процесс прослушивает этот порт.

Второе, что нужно проверить, это то, что вы корректно закрываете сокет, когда ваше приложение закрывается. Если вы используете API сокетов высокого уровня, это не должно быть большой проблемой (вы используете API сокетов, верно?).

Наконец, как устроено ваше приложение? Он резьбовой? Он запускает другие процессы? Как узнать, что ваше приложение действительно закрыто?

person Thomi    schedule 16.12.2010
comment
добавлено уточнение + вывод netstat -anb, также я проверил с помощью диспетчера задач, процесс приложения определенно ушел, и он не порождает никаких других процессов. - person BrokenGlass; 16.12.2010

Бегать

netstat -ано

Это даст вам PID процесса, у которого открыт порт. Проверьте этот процесс в диспетчере задач. Убедитесь, что у вас установлен флажок «Список процессов от всех пользователей».

person Virtually Real    schedule 17.12.2010
comment
Бьюсь об заклад, Система держит его открытым, но я могу ошибаться. - person Virtually Real; 17.12.2010
comment
Это указывает на то, что какая-то служба Windows держит ее открытой, возможно, это служба, запущенная вашим приложением косвенно. Я бы посоветовал вам отключить запущенные службы одну за другой и посмотреть, свободен ли порт (или, по крайней мере, перешел ли он в состояние time_wait). Если это так, вы можете полностью отключить эту службу. Пожалуйста, опубликуйте свои выводы. - person Virtually Real; 18.12.2010

http://hea-www.harvard.edu/%7Efine/Tech/addrinuse.html — отличный ресурс для ошибок Bind: Адрес уже используется.

Некоторые выдержки:

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

Стратегии уклонения

SO_REUSEADDR

Это одновременно и самый простой, и самый эффективный способ уменьшить ошибку уже используемого адреса.

Клиент закрывается первым

TIME_WAIT можно избежать, если удаленный конец инициирует закрытие. Таким образом, сервер может избежать проблем, позволив клиенту закрыться первым.

Уменьшить время ожидания

Если (по какой-либо причине) ни один из этих вариантов вам не подходит, можно также сократить время ожидания, связанное с TIME_WAIT.

person pba    schedule 13.01.2015

Увидев https://superuser.com/a/453827/56937, я обнаружил, что WerFault процесс был приостановлен .

Должно быть, он унаследовал сокеты от несуществующего процесса, потому что его уничтожение освободило мои прослушивающие порты.

person Gabe    schedule 17.04.2015