Socket read () зависает некоторое время, когда нет данных для чтения - PullRequest
2 голосов
/ 24 мая 2010

Привет, я пишу простой http перенаправитель портов. Я читаю данные с порта 80 и передаю данные на мой сервер lighttpd через порт 8080.

Пока я записываю () данные в сокет на порту 8080 (пересылка запроса), проблем нет, но когда я читаю () данные из этого сокета (пересылаем ответ), последнее чтение () много зависает (около 1 или 2 секунд), прежде чем понять, что больше нет данных и вернуть 0.

Я попытался установить сокет в неблокирующее состояние, но это не работает, так как иногда он возвращает EWOULDBLOCKING, даже если остались некоторые данные (lighttpd + cgi может быть довольно медленным). Я попытался установить тайм-аут с помощью select (), но, как и выше, медленный cgi мог тайм-аут сокета, когда на самом деле есть какие-то данные для передачи.


Обновление: решено. Это был keepalive в конце концов. После того, как я отключил его в своем файле конфигурации lighttpd, все работает без сбоев.

Ответы [ 4 ]

2 голосов
/ 25 мая 2010

Что ж, ради завершения и согласно моему комментарию:

Вполне вероятно, что сам HTTP-сервер (lighttpd в вашем случае) поддерживает постоянное соединение с вашим прокси, потому что ваш прокси ретранслируетзаголовок, содержащий «Connection: keep-alive».Этот заголовок помогает, когда клиент хочет сделать несколько запросов по одному соединению.Таким образом, поскольку lighttpd получил этот заголовок, он предполагал, что получит дополнительные запросы, и оставит сокет открытым, что приведет к блокировке read в вашем прокси.

Отключение поддержки активности в конфигурации lighttpd - это один из способовчтобы исправить это, но вы также можете удалить «Connection: keep-alive» из заголовка, прежде чем передать его на свой веб-сервер.

1 голос
/ 27 августа 2011

Не делайте этого!

Keepalive повышают производительность других клиентов.Вместо этого исправьте свой клиент.Отправьте заголовок Connection: close на своем клиенте и убедитесь, что ваш запрос не требует HTTP/1.1 соответствия.(Если по какой-либо иной причине вы, вероятно, тоже не обрабатываете чанкованное кодирование.)

1 голос
/ 24 мая 2010

Использование обеих неблокирующих розеток и select - правильный путь.Возвращение EWLOULDBLOCK не означает, что весь поток данных закончен, получая, это означает, что мгновенно нечего читать прямо сейчас.Это именно то, что вы хотите, потому что это означает, что read не будет ждать даже полсекунды, чтобы появилось больше данных.Если данные не сразу доступны, они вернутся.

Теперь, очевидно, это означает, что вам нужно будет несколько раз вызвать read, чтобы получить полные данные.Общий формат для этого - цикл выбора.В псевдокоде:

do
  select ( my_sockets )

  if ( select error ) 
    handle_error
  else
    for each ( socket in my_sockets ) do
      if ( socket is ready ) then
        nonblocking read from socket
        if ( no data was read ) then
          close socket
          remove socket from my_sockets
        endif
      endif
    loop
  endif
loop

Идея состоит в том, что select скажет вам, какие сокеты имеют данные для чтения прямо сейчас .Если вы прочитаете один из этих сокетов, вы гарантированно либо получите данные, либо получите возвращаемое значение 0, указывающее, что удаленный конец закрыл сокет.

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

0 голосов
/ 24 мая 2010

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

while(select(...)) {
    switch(...) {
    case ...: // Handle accepting new connection
    case ...: // Handle reading from socket
    ...
    }
}

Sinle-thread, блокировка пересылки в любом случае вызовет проблемы с несколькими клиентами.

Извините - я не помню точных звонков. Также это может быть странно в некоторых случаях (IIRC - вам нужно обрабатывать запись), но есть библиотеки, которые упрощают задачу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...