Программно определить, завис ли локальный веб-сервер

Я понимаю, что получу по крайней мере один ответ в духе «(пере)пишите код, чтобы он не зависал», но давайте предположим, что мы еще не живем в этой блестящей счастливой утопии...

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

Возможно, во время определенных фаз луны что-то может привести к зависанию веб-сервера или иной зависанию таким образом, что процесс будет казаться работающим нормально (без сбоя/неработоспособности/использования ЦП на 100 %). ), но не обслуживает никаких веб-страниц.

Итак, вопрос в том, как мы можем проверить/обнаружить эту ситуацию?


person John U    schedule 01.10.2014    source источник
comment
Отправить небольшой, четко определенный запрос и убедиться, что вы получите ожидаемый ответ в течение заданного срока?   -  person isedev    schedule 01.10.2014
comment
Ну, да, я как бы догадался, что общие штрихи будут такого порядка, что мне нужно, это метод отправки HTTP-запроса или аналогичный веб-серверу с минимальными затратами.   -  person John U    schedule 01.10.2014
comment
Простым решением будет сценарий оболочки, выполняющий wget -q -O /dev/null TESTURL и проверяющий код состояния, возвращаемый wget.   -  person isedev    schedule 01.10.2014


Ответы (1)


Чтобы проверить, завис ли сервер, создайте TCP-сокет и подключитесь к порту 80 по IP-адресу 127.0.0.1 (адрес обратной связи). Затем отправьте следующий текст через сокет

GET / HTTP/1.1\r\n\r\n

Большинство серверов интерпретируют это как запрос index.html. В качестве альтернативы вы можете реализовать недокументированный URL-адрес для тестирования (который позволяет получить более короткий заранее определенный ответ), например.

GET /test/fdoaoqfaf12491r2h1rfda HTTP/1.1\r\n\r\n

Затем вам нужно прочитать ответ от сервера. Это включает в себя использование select с разумным временем ожидания, чтобы определить, вернулись ли какие-либо данные с сервера, и если да, используйте recv для чтения данных. Ответ от сервера будет состоять из заголовка, за которым следует содержимое. Заголовок состоит из строк текста с пустой строкой в ​​конце заголовка. Строки заканчиваются на \r\n, поэтому конец заголовка — \r\n\r\n.

Получение содержимого включает вызов select и recv до тех пор, пока recv не вернет 0. Это предполагает, что сервер отправит ответ, а затем закроет сокет. Некоторые сложные серверы оставляют сокет открытым, чтобы разрешить несколько запросов через один и тот же сокет. Простой встроенный сервер не должен этого делать. (Если ваш сервер пытается использовать один и тот же сокет для нескольких запросов, вам нужно выяснить, как отключить эту функцию.)


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

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

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

Затем вам нужно создать клиент, который преднамеренно ведет себя неправильно. Клиенты могут плохо себя вести

  • оставить сокет открытым без чтения ответа сервера
  • резкое закрытие сокета при чтении ответа
  • изящное закрытие сокета при чтении ответа

Первая ситуация должна быть обработана тайм-аутом TCP. Два других должны быть правильно обработаны серверным кодом. Изящное и резкое закрытие сокета управляется параметром SO_LINGER функции ioctl и функцией shutdown. После неправильного поведения клиента проверьте количество дескрипторов открытых файлов. в серверном процессе, чтобы убедиться, что сервер правильно обработал ситуацию.

person user3386109    schedule 01.10.2014
comment
Хороший ответ. Ссылка на 2-ю половину: это не мой код, это Boa, который был взломан Elbonian Code Slaves как часть массивного волосатого и недокументированного SDK, зависания происходят из-за неудачных вызовов других частей SDK, мы постепенно бреем его и избиение его до подчинения, но искоренение всех неприятных вещей может занять человеко-годы, поэтому смягчение последствий — наш лучший вариант в качестве лейкопластыря. - person John U; 02.10.2014
comment
Я слышу тебя, и прими мои соболезнования. Удивительно, насколько плох некоторый код с открытым исходным кодом, учитывая его очевидное широкое распространение. В какой-то момент вам придется решить, лучше ли начать с нуля, чем тратить человеко-годы на распутывание чужого комка спагетти. В моем случае я законсервировал код стороннего сервера и сделал свой собственный. - person user3386109; 02.10.2014
comment
Хуже того, это коммерческий SDK от Texas Instruments, хотя они пытаются дистанцироваться от стороннего Elbonian оборудования, которое произвело большую часть этого от их имени. - person John U; 03.10.2014