Fakeman
Новичок
Неблокирующий сокеты и чтение gzip-контента
Написал я многопоточный скрипт для работы с неблокирующими сокетами с помощью функций socket_*. Работает скрипт в одном проектике, все вроде отлично. Но тут мне понадобилось загрузить страницу с одного сайта, которая случайно оказалась закодирована gzip. И вот тут мой скриптик меня подвел.
Почему-то не завершается чтение сокета. Может кто-то сталкивался, может есть какая-то тонкость в работе с зазипованным контентом?
Для лучшего понимания проблемы приведу дополнительную информацию. Простите за много букв, но дабы не быть голословным, привожу данные протоколирования (встроено в мой класс) и примерный кусок кода.
Вот лог обращения к странице, которая не закодирована gzip:
[00:01:46] log opened
[00:01:46] socket 8: connect to www.site.ru (XX.XXX.XX.XX:80) - сокет сконнектился
[00:01:46] 1 socket(s) in process - перед вызовом socket_select
[00:01:48] 1 socket(s) change state, 1 for write, 0 for read - результат socket_select
[00:01:48] socket 8: is ready - перед socket_write
[00:01:48] socket 8: request size is 319
[00:01:48] socket 8: 319 bytes written - socket_write
[00:01:50] 1 socket(s) in process
[00:01:50] 1 socket(s) change state, 0 for write, 1 for read - результат socket_select
[00:01:50] socket 8: 8192 bytes read
[00:01:54] 1 socket(s) in process
[00:02:00] 1 socket(s) change state, 0 for write, 1 for read
[00:02:00] socket 8: 4319 bytes read
[00:02:02] 1 socket(s) in process
[00:02:02] 1 socket(s) change state, 0 for write, 1 for read
[00:02:02] socket 8: read completely - все прочитано
[00:02:02] socket 8: closed
[00:02:04] log closed
А вот лог при считывании страницы, закодированной gzip:
[00:01:46] log opened
[00:01:46] socket 8: connect to www.site.ru (XX.XXX.XX.XX:80) - сокет сконнектился
[00:01:46] 1 socket(s) in process - перед вызовом socket_select
[00:01:48] 1 socket(s) change state, 1 for write, 0 for read - результат socket_select
[00:01:48] socket 8: is ready - перед socket_write
[00:01:48] socket 8: request size is 319
[00:01:48] socket 8: 319 bytes written - socket_write
[00:01:50] 1 socket(s) in process
[00:01:50] 1 socket(s) change state, 0 for write, 1 for read - результат socket_select
[00:01:50] socket 8: 8192 bytes read
[00:01:54] 1 socket(s) in process
[00:02:00] 1 socket(s) change state, 0 for write, 1 for read - результат socket_select
[00:02:00] socket 8: 4319 bytes read
[00:02:02] 1 socket(s) in process
[00:02:03] 1 socket(s) in process
[00:02:04] 1 socket(s) in process
[00:02:05] 1 socket(s) in process
[00:02:06] 1 socket(s) in process
... итак до конца
Другими словами socket_select выдает 0 изменившихся сокетов и цикл обработки просто подвисает.
Коротко алгоритм:
Есть у кого-нибудь мысли?
Написал я многопоточный скрипт для работы с неблокирующими сокетами с помощью функций socket_*. Работает скрипт в одном проектике, все вроде отлично. Но тут мне понадобилось загрузить страницу с одного сайта, которая случайно оказалась закодирована gzip. И вот тут мой скриптик меня подвел.
Почему-то не завершается чтение сокета. Может кто-то сталкивался, может есть какая-то тонкость в работе с зазипованным контентом?Для лучшего понимания проблемы приведу дополнительную информацию. Простите за много букв, но дабы не быть голословным, привожу данные протоколирования (встроено в мой класс) и примерный кусок кода.
Вот лог обращения к странице, которая не закодирована gzip:
[00:01:46] log opened
[00:01:46] socket 8: connect to www.site.ru (XX.XXX.XX.XX:80) - сокет сконнектился
[00:01:46] 1 socket(s) in process - перед вызовом socket_select
[00:01:48] 1 socket(s) change state, 1 for write, 0 for read - результат socket_select
[00:01:48] socket 8: is ready - перед socket_write
[00:01:48] socket 8: request size is 319
[00:01:48] socket 8: 319 bytes written - socket_write
[00:01:50] 1 socket(s) in process
[00:01:50] 1 socket(s) change state, 0 for write, 1 for read - результат socket_select
[00:01:50] socket 8: 8192 bytes read
[00:01:54] 1 socket(s) in process
[00:02:00] 1 socket(s) change state, 0 for write, 1 for read
[00:02:00] socket 8: 4319 bytes read
[00:02:02] 1 socket(s) in process
[00:02:02] 1 socket(s) change state, 0 for write, 1 for read
[00:02:02] socket 8: read completely - все прочитано
[00:02:02] socket 8: closed
[00:02:04] log closed
А вот лог при считывании страницы, закодированной gzip:
[00:01:46] log opened
[00:01:46] socket 8: connect to www.site.ru (XX.XXX.XX.XX:80) - сокет сконнектился
[00:01:46] 1 socket(s) in process - перед вызовом socket_select
[00:01:48] 1 socket(s) change state, 1 for write, 0 for read - результат socket_select
[00:01:48] socket 8: is ready - перед socket_write
[00:01:48] socket 8: request size is 319
[00:01:48] socket 8: 319 bytes written - socket_write
[00:01:50] 1 socket(s) in process
[00:01:50] 1 socket(s) change state, 0 for write, 1 for read - результат socket_select
[00:01:50] socket 8: 8192 bytes read
[00:01:54] 1 socket(s) in process
[00:02:00] 1 socket(s) change state, 0 for write, 1 for read - результат socket_select
[00:02:00] socket 8: 4319 bytes read
[00:02:02] 1 socket(s) in process
[00:02:03] 1 socket(s) in process
[00:02:04] 1 socket(s) in process
[00:02:05] 1 socket(s) in process
[00:02:06] 1 socket(s) in process
... итак до конца
Другими словами socket_select выдает 0 изменившихся сокетов и цикл обработки просто подвисает.

Коротко алгоритм:
PHP:
while ( count ( $this->sockets ) > 0 ) {
$this->logger->write ( count ( $this->sockets ) . " socket(s) in process" );
$changed_sockets = socket_select ( $read, $write, $except, 0);
if ( $changed_sockets === false ) {
$this->logger->write ( "couldn't select sockets" );
return false;
} elseif ( $changed_sockets > 0 ) {
$this->logger->write ( $changed_sockets . " socket(s) change state, " . count ( $write ) . " for write, " . count ( $read ) . " for read" );
//читам или пишем сокеты
}
usleep ( SLEEP_TIME );
}