С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 09/12/07 в 03:51 |
я именно так и делаю.
Перефразирую вопрос, как узнать что это именно eof? Сейчас я закрываю сокет если он выбрался на чтение и не вернул данных.
|
|
|
|
С нами с 01.03.06
Сообщения: 629
Рейтинг: 620
|
Добавлено: 09/12/07 в 04:02 |
Может и туплю, но понятие eof относительно.
eof определить можно как:
1. по таймауту.
2. по ошибке
3. по закрытому/оборванному на другой стороне соединению
4. внутреннему определению конца данных, заложенных "протоколом" обмена. например, в том же http это может быть content-length (или как там его).
|
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 09/12/07 в 05:46 |
Sirgey писал: | Перефразирую вопрос, как узнать что это именно eof? |
feof()? fread()===false?
Heavy: тупишь.
1. таймаут в данном случае имеет отношение к селекту а не к fread/fgets. В то время как EOF выскакивает как раз в процессе fread/fgets
2. Ошибок тут может быть две - это закрытие сокета другой стороной или сетевые проблемы. В этом случае EOF так же выскочит в результате fread. Ну ООМ я не считаю )
3. тоже
4. Мы читаем на уровне намного ниже чем протокол HTTP. Это неуместно. Даже если ты имел ввиду протокол TCP/IP, то все эти внутренние определения уже заложены в fread/fgets.
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 09/12/07 в 06:45 |
Код: | $b = @socket_read($arrRead[$index], 2048, PHP_BINARY_READ);
if ($b === false)
{
if (debug) echo "close coket<hr>\n"; flush();
socket_close($arrRead[$index]);
unset($arrRead[$index]);
}
else
{
if (debug) echo "read: ".strlen($b)." bytes<hr>\n"; flush();
$buf[$index] .= $b;
} |
Вот такой код не работает. socket_read никогда не возвращает булевый false.
Соответственно раньше было вместо '===' !$b. Закрывало когда пустую строку выдавало, некоторые сокеты после записи сразу отдавали пустоту, хотя и были доступными на чтение
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 09/12/07 в 06:50 |
Э.... сори, народ. Я тупанул. Не по тому массиву ездил для чтения (по исходному). Счас поправил - заработало.
Проверять на конец файла не надо, с сокетами это не работает. Надо вот так:
Код: | if (!($b = @socket_read($arrRead[$index], 2048, PHP_BINARY_READ)))
{
if (debug) echo "close coket<hr>\n"; flush();
socket_close($arrRead[$index]);
unset($arrRead[$index]);
}
else
{
if (debug) echo "read: ".strlen($b)." bytes<hr>\n"; flush();
$buf[$index] .= $b;
} |
|
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 09/12/07 в 13:21 |
ну, так я ж тебе и грю, EOF это когда fread()===false
|
|
|
|
С нами с 01.03.06
Сообщения: 629
Рейтинг: 620
|
Добавлено: 09/12/07 в 14:11 |
Pentarh писал: |
Heavy: тупишь.
|
ну насамом деле не совсем ;)
Pentarh писал: |
1. таймаут в данном случае имеет отношение к селекту а не к fread/fgets. В то время как EOF выскакивает как раз в процессе fread/fgets
|
По такому принципу, получается, что если отдающая сторона сделала паузу в передаче данных, уже считать что наступил eof? Какраз-таки система таймаутов тут и помогает, иначе возникнет следующий топик - получил eof - а данные оборваны на середине.
Pentarh писал: |
4. Мы читаем на уровне намного ниже чем протокол HTTP. Это неуместно. Даже если ты имел ввиду протокол TCP/IP, то все эти внутренние определения уже заложены в fread/fgets. |
Ну приехали, причем тут на каком уровне вы читаете ) открой сокет и пошли keep-alive запрос на http сервер - сколько еофа будешь ждать - до морковного заговения? и смысл его ждать, если можно сокет дальше реюзать спокойно хотя стоп - конечно же - умный fread скажет EOFFF как толко перестанут поступать данные... а кто сказал что это все что хотел ответить сервер на запрос? следующее чтение выгребет то что осталось в буфере и опят ьбудет каша. (конечно есть выход - закрывать сокет и плевать - дочитали или нет).
То что заложено протоколом TCP/IP - ок не вопрос - обрабатывает библиотека, но все что в стеке выше - обрабатывает только программист (или промежуточная либа), и надеятся на корректную обработку eof-а от либы сокетов не стоит.
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 09/12/07 в 15:26 |
Цитата: | ну, так я ж тебе и грю, EOF это когда fread()===false |
Ты не правильно говоришь. Во первых fread === false, это не eof, a ошибка чтения. Во вторых fread неприменим к сокетам. А в третьих сокет никогда не возвращает булевый false.
Посмотри код, последний, там явно видно что сравнение не по типу, а по пустоте (empty было - бы правильно).
Heavy, Pentarh правильно говорит в том о чём вы спорите Если отдающая сторона сделала паузу, то сокет не вернётся из селекта на чтение (он данных потому - что не отдаёт).
Система таймаутов помогает не eof найти, а предотвратить зависание из - за слишком медленно отвечающих серверов (или вообще не отвечающих).
EOF, как я уже говорил, к сокетам неприминим (End Of File, сокет это не файл).
Вообще, броузер должен читать ответ сервера как раз по длине указанной в хедере. Проверь - если ты посылаешь не страницу, а пост или картинку и неправильный content-length сделаешь - то броузер считает только твою длинну указанну, а остальное отбросит.
Насчёт текста, html и там где размер не указан - хер его знает что броузер делает. Наверное там всё сложнее.
Учти ещё, что в протоколе TCP/IP имеется возможность запросить заново пакеты, а в сокетах этого нету, тут по сути только содержимое пакетов отдают, а сами пакеты обрабатываются в недрах. Наверняка есть возможность закрытия соединения спец.пакетом. и проверки закрытия / открытости. Но нам всё это пакетом не предоставлено, значит будем пользоваться тем что есть
|
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 09/12/07 в 15:47 |
Heavy писал: | По такому принципу, получается, что если отдающая сторона сделала паузу в передаче данных, уже считать что наступил eof? Какраз-таки система таймаутов тут и помогает, иначе возникнет следующий топик - получил eof - а данные оборваны на середине. |
Ты не понимаешь о чем мы вообще говорим тут. "man 2 select" набери и почитай. При вызове select() на read вектор, эта функция погружает приложение в sleep в течении максимально указанного таймаута пока на сокет не прийдут данные для чтения. Т.е. если селект вернул TRUE, то в сокете ЕСТЬ что прочитать иначе - таймаут селекта и FALSE.
Если таймаут в селекте указывать небольшим (десятки микросекунд), мы получаем эффект "поллинга".
if (select(..)) {
сокет готов, есть что читать, читаем
} else {
сокет не готов, данные не пришли еще, откладываем его, берем другой сокет
}
Причем данные идут порционно. Примерно по MTU байт. N байт прочитал, отложил сокет пока туда прийдет очередная порция, взял следующий.
Heavy писал: |
Ну приехали, причем тут на каком уровне вы читаете ) открой сокет и пошли keep-alive запрос на http сервер - сколько еофа будешь ждать - до морковного заговения? |
Ну вот, ты опять некомпетентен. keep-alive это фишка HTTP, а socket_read намного ниже стоит по уровню протокола. Ты хоть кип элайв туда посылай, хоть нет, после последнего байта ответа прийдет EOF, который проявится в том что socket_read() вернет FALSE. Но в случае keep-alive, удаленная сторона сокет не закроет, а будет ждать следующего вызова. В этом случае надо уже проверять сокет select'ом на write, и если готов, писать следующий запрос и читать ответ.
Heavy писал: | и смысл его ждать, если можно сокет дальше реюзать спокойно хотя стоп - конечно же - умный fread скажет EOFFF как толко перестанут поступать данные... а кто сказал что это все что хотел ответить сервер на запрос? |
Еще раз повторяю для тех кто в танке.
if (select(на чтение)) {
$buf=socket_read();
}
В этой конструкции socket_read может вернуть FALSE только в двух случаях:
1. Удаленный сервер полностью высказался.
2. Произошла межсетевая ошибка.
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 09/12/07 в 15:56 |
Pentarh, я тестил, возможно это в php так собрано, но у меня socket_read не возвращает false, а взвращает просто пустоту.
Если я проверяю по типу, т.е. === false, то происходит зацикливание с пустым ответом каждый раз (именно пустым, а не false).
|
|
|
|
С нами с 01.03.06
Сообщения: 629
Рейтинг: 620
|
Добавлено: 09/12/07 в 16:02 |
Sirgey писал: | Heavy, Pentarh правильно говорит в том о чём вы спорите Если отдающая сторона сделала паузу, то сокет не вернётся из селекта на чтение (он данных потому - что не отдаёт).
|
если не ошибаюсь, то тема про асинхронное чтение - т.е. если в буфере ничего нету- то какраз-таки тотже fread верентся с пустым значением и не будет ждать появления данных. для синхронного варианта - да - будет ждать минимального одного байта данных либо наступления тафмаута/разрыва или еще какого события.
Sirgey писал: | Система таймаутов помогает не eof найти, а предотвратить зависание из - за слишком медленно отвечающих серверов (или вообще не отвечающих).
|
именно так и есть, просто использовать внутренний механизм имхо удобнее чем наворачивать свой поверх на пыхе ;)
Sirgey писал: | EOF, как я уже говорил, к сокетам неприминим (End Of File, сокет это не файл).
|
если работа идет с сокетом как со стримом - то отношение имеет, только ловить его не в fread() стоит, а в feof() - но насколько помню - действие сей функции ограничивается сугобо отловом разрыва соединения с противоположной стороной, либо достижения таймаута. т.е. пологатся сугубо на эту функцию, имхо не стоит, но и опускать тоже ;)
Sirgey писал: | Вообще, броузер должен читать ответ сервера как раз по длине указанной в хедере. Проверь - если ты посылаешь не страницу, а пост или картинку и неправильный content-length сделаешь - то броузер считает только твою длинну указанну, а остальное отбросит. |
браузер так и делает
Sirgey писал: | Насчёт текста, html и там где размер не указан - хер его знает что броузер делает. Наверное там всё сложнее. |
нет. ничего сложнее там и нету - см. предыдущий свой абзац - все определяется content-length, неважно какой тип контента ты запросил - главное что ты запросил по протоколу HTTP - т.е. по протоколу, в заголовке ответа тебе обязательно дожно прийти сколько данных тебе ожидать в ответ и сколько всего имеется (если запрос HEAD или указан RANGE).
Sirgey писал: | Учти ещё, что в протоколе TCP/IP имеется возможность запросить заново пакеты, а в сокетах этого нету, тут по сути только содержимое пакетов отдают, а сами пакеты обрабатываются в недрах. Наверняка есть возможность закрытия соединения спец.пакетом. и проверки закрытия / открытости. Но нам всё это пакетом не предоставлено, значит будем пользоваться тем что есть |
не путайте "сокеты". то чем пользуется тот же пых = это только надстройка. добратся до дебрей TCP/IP так просто не получится, да и надобности нет - не боитесь там все делается хорошо и правильно - и мешать этому механизму работать не стоит ;)
|
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 09/12/07 в 16:04 |
Ну вообще да, у пхп порой странные понятия об true и false, null и пустоте.
Sirgey писал: | Ты не правильно говоришь. Во первых fread === false, это не eof, a ошибка чтения. Во вторых fread неприменим к сокетам. А в третьих сокет никогда не возвращает булевый false.
Посмотри код, последний, там явно видно что сравнение не по типу, а по пустоте (empty было - бы правильно).
|
Дело в том что пых-пых очень тяжелый язык для таких высоких материй и я на нем такие вещи не пишу. В качестве fread я имел ввиду операцию чтения из сокета.
Но поскольку все эти select(), socket_read() и пр. являются прямыми биндингами соответствующих системных вызовов, которые справедливы для любого языка, то мне не обязательно знать как эта функция называется в пхп, что она в каком случае возвращает и как реагирует. Везде это практически одинаково.
Да, fread() равно false/пустота это ошибка чтения, в подавляющем большинстве случаев причиной является EOF. По этому и пишут while ($buf=fread()) {..} Ну можно конечно еще дописать код диагностики ошибки, но данных тебе это не вернет. На ошибке чтения будет конец данных в любом случае.
|
|
|
|
С нами с 01.03.06
Сообщения: 629
Рейтинг: 620
|
Добавлено: 09/12/07 в 16:11 |
Pentarh писал: | Ты не понимаешь о чем мы вообще говорим тут. "man 2 select" набери и почитай. При вызове select() на read вектор, эта функция погружает приложение в sleep в течении максимально указанного таймаута пока на сокет не прийдут данные для чтения. Т.е. если селект вернул TRUE, то в сокете ЕСТЬ что прочитать иначе - таймаут селекта и FALSE.
|
ок. колупайтесь в свой песочнице дальше, просто намешали в топике select() c fread() - одни про одно другие про другое ))
но вообще не очень хорошо работать только по "низкому" протоколу с протоколом стоящим на несколько ступенек выше по стеку. полюбому все определяет конкретная задача.
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 09/12/07 в 16:40 |
Цитата: | если не ошибаюсь, то тема про асинхронное чтение - т.е. если в буфере ничего нету... |
ошибаешься.
Цитата: | именно так и есть, просто использовать внутренний механизм... |
вообще не в тему предыдущих твоих сообщений. Мы как раз тебе про внутренние механизмы говорим - а ты говоришь что таймауты надо использовать.
Цитата: | если работа идет с сокетом как со стримом - то отношение имеет, только ловить его не в fread() стоит, а в feof()... |
Не имеет в любом случае. Ни стрим ни сам собственно сокет это не файл, и файловые функции для него неприменимы. Даже если они срабатывают.
Цитата: | браузер так и делает |
Браузер не так делает. Не передавай длину, и тогда он считает всё правильно, до конца. Даже если ты паузу перед последним байтом сделаешь. Это значит что руководствуется он как раз разбором TCP/IP протоколом, возможно через виндозные сокеты (линуксовые сокеты), но всё - же им, а не HTTP протоколом.
Как там всё делается - имел возможность наблюдать - поверь, там так всё делается, что порой страшно становится за всё то сообщество котороё на нём пишет серьёзные проекты.
|
|
|
|
С нами с 11.06.03
Сообщения: 1266
Рейтинг: 950
|
Добавлено: 09/12/07 в 18:16 |
Кончайте детский сад.
Привожу каноническое использование "мультизакачки". Написал на скорую руку.
Для полноценного использования необходимо уметь по дескриптору сокета находить соответствующий контекст.
Возникает желание селект внести в скобки с соответствующим разбрасыванием usleep (как у Pentarh'a) , но тогда селект становится ненужным и комп бессмысленно пробуксовывает более или менее в зависимости от величины выбранной паузы. Приходится вручную искать компромисс между загрузкой процессора и скоростью закачки.
Код: |
<?php
$peers = Array (
Array ('site'=>'www.google.com','port'=>80,),
Array ('site'=>'www.rambler.ru','port'=>80),
Array ('site'=>'spam.spam.com','port'=>25)
);
$sockets = Array();
$i=0;
foreach ($peers as $peer) {
$sockets[$i] = Array('handle'=>false, 'stage'=>0);
if (false === ($sockets[$i]['handle']=fsockopen($peer['site'],$peer['port']))) {
/* error print whatever you want */
} else {
stream_set_blocking($socket[$i]['handle'],0)
$i++;
}
}
$timeout = 10;
$quit = 0;
while (!$quit) {
$toread = Array();
$towrite = Array();
$num = 0;
foreach ($sockets as $socket) {
if (false === $socket['handle']) {
} else {
if (0 == $socket['stage']) {
// Запрос не отослан
$towrite[]=$socket['handle'];
$num++;
} else if (1 == $socket['stage']) {
// Запрос отослан ответ не полностью считан
$toread[]=$socket['handle'];
$num++;
} else {
// Всё украдено до нас, но как ?
fclose($socket['handle']);
$socket['handle']=false;
}
}
}
if (0==$num) {
// никого нет
$quit = 1;
} else {
// собственно селект
$res = stream_select($toread,$towrite,$err=NULL,$timeout)) {
if (false === $res) {
// фатальная ошибка
$quit = 1;
} else if (0 == $res) {
// timeout
$quit = 1;
} else {
foreach ($toread as $sock) {
// ВНИМАНИЕ необходимо понять чей это сокет, найти соответствующий элемент массива
if (feof($sock)) {
// закройте соответствующий сокет и присвойте элементу 'handle' массива false
} else {
// читайте с сокета.
}
}
foreach ($towrite as $sock) {
// аналогично чтению найдите элемент массива $sockets соответствующий значению $sock чтобы знать что писать и куда отмечать ошибки. При отправке конца запроса измените значение 'stage' элемента на 1
}
}
}
}
?>
|
Последний раз редактировалось: Sha (10/12/07 в 11:28), всего редактировалось 1 раз
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 10/12/07 в 04:25 |
Всё перемешал, сокеты, стримы, файловые функции... Это как раз на тему что даже если они всем вместе работают - не значит что надо так делать (тупо потому - что они из разных пакетов, и в следующей реализации это всё может не работать)
Не буду выкладывать свою версию, не думаю что она того достойна, если надо кому - покажу.[/code]
|
|
|
|
С нами с 11.06.03
Сообщения: 1266
Рейтинг: 950
|
Добавлено: 10/12/07 в 09:19 |
Не надо "ля-ля". Читай документацию.
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 13/12/07 в 00:51 |
Не буду Прости меня
Вообще зачётный топик получился. Ещё вот такой вопрос: ни у кого артефакты не появлялись при закачках? (числа в потоке), например вот так:
Код: | Бла-бла-бла
866
бла-бла-бла |
Где бла - бла- бла это то что надо, а вот цифра х.з. откуда взялась. В исходных данных этого нет.
|
|
|
|
Best4U.Biz
С нами с 21.02.04
Сообщения: 1252
Рейтинг: 1441
|
Добавлено: 13/12/07 в 02:04 |
Это чунки
Лечится выдачей нужного ассепт-енкодинг в запросе
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 13/12/07 в 02:37 |
Цитата: | Это чунки
Лечится выдачей нужного ассепт-енкодинг в запросе |
Если я не ошибаюсь чунки - это служебные данные которые апач передаёт.... Надо запрашивать нужный (utf-8 например) или конвертить по прибытию пакета?
Или отдавать нужную кодировку надо?
|
|
|
|
С нами с 11.06.03
Сообщения: 1266
Рейтинг: 950
|
Добавлено: 13/12/07 в 11:02 |
Sirgey писал: | Если я не ошибаюсь чунки - это служебные данные которые апач передаёт.... Надо запрашивать нужный (utf-8 например) или конвертить по прибытию пакета?
Или отдавать нужную кодировку надо? |
Указание на соответствующее кодирование может появиться в виде заголовка
Transfer-Encoding: chunked
реже в Content-Transfer-Encoding: chunked
К сожалению не лечится выдачей соответствующего Accept-Encoding. (Sams не прав) Accept-Encoding относится к контенту, а "chunked" к трансферу.
Собственно во избежание геморроя настоятельно рекоммендуется использовать curl multy-функции чтобы не разбирать всю эту порнуху. Всё в curl уже продумано до вас.
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 15/12/07 в 20:28 |
Ну в своём загрузчике я вроде всё починил (перешёл на протокол 1.0). А вообще - на русском не знаешь перевода этого аспекта протокола? Типа как разбирать самому что такой вот префикс пришёл.
|
|
|
|
Best4U.Biz
С нами с 21.02.04
Сообщения: 1252
Рейтинг: 1441
|
Добавлено: 15/12/07 в 22:44 |
Sha писал: | К сожалению не лечится выдачей соответствующего Accept-Encoding. (Sams не прав) Accept-Encoding относится к контенту, а "chunked" к трансферу. |
В теории - ты прав. На практике - от конкретных сайтов я добивался передачи без чунков перебором Accept-Encoding. Там есть какая-то взаимосвязь.
Разбор - прост до безобразия. Контент идет в таком виде:
цифра\r\n
контент\r\n
цифра\r\n
контент\r\n
00\r\n
где цифра - это кол-во байт в следующем чунке, в шестнадцатеричном счислении.
|
|
|
|
С нами с 11.06.03
Сообщения: 1266
Рейтинг: 950
|
Добавлено: 16/12/07 в 20:57 |
Sams писал: | На практике - от конкретных сайтов я добивался передачи без чунков перебором Accept-Encoding. Там есть какая-то взаимосвязь. |
Вообще хотелось бы посмотреть на такие серверы.
Статика итак обычно передается без чунков. Но вот динамика большой вопрос. Если скрипт не в состоянии указать серверу предварительно размер, то скорее всего будут чунки и перебор accept'а не спасет.
|
|
|
|
С нами с 16.04.05
Сообщения: 754
Рейтинг: 352
|
Добавлено: 17/12/07 в 11:56 |
А если указывать фиксированный размер при отдаче контента?
Цитата: | цифра\r\n
контент\r\n
цифра\r\n
контент\r\n
00\r\n |
такую херь не отфильтруешь, надо ниже протоколом спускаться....
|
|
|
|