winsock recv

интернет программирование программы Delphi winsock

Пишу программу на delphi с использованием winsock. Точней аналог IdHTTp из Indy, т.к. в Indy он глючный. В общем, отправляю заголовок, приходит ответ, но не полностью, он обрезается. Ну, думаю, ладно, ошибся, бывает. Включу сниффер и увижу, что что-то не так отправил. Запустил HttpAnalyzer, поставил трафик на прослушку - все заработало(пришла целая страница, и в программе и в сниффере). Отключил сниффер - опять режется, попробовал еще раз - результат тот же. Если бы и с включенным сниффером ответ обрезался бы - это я еще понимаю, но ЭТО уже ни в какие ворота не лезет.
Если кратко, то код примерно слдующий:
var
buf:array[0..255] of ansichar;
begin
j:=length(msg.Mess);
ErrorCode:=send(Sock,msg.Mess[1],j,0);
j:=length(buf);
repeat
FillChar(buf,Length(buf),0);
ErrorCode:=recv(Sock,buf[0],j,0);
if ErrorCode=-1 then
MessageBox(0,'Error Recv','Error',0);
Result:=Result+buf;
until ErrorCode<Length(buf);

end;
В чем может быть проблема? Сокеты использую блокирующие. Могу выложить весь код, если потребуется, но воздействие сниффера на программу меня "чуть-чуть" удивило.

Примечание:
Я пытался еще раз вызывать recv после цикла, но он подвисал секунд на 20, а данные так и не приходили...

Примечание:
В общем, так... Вроде, понял почему возникает проблема. Видимо, когда я вызываю recv, в буфер winsock передаются с сервера еще не все данные(не вся страница) и копируется в buf лишь то, что уже успело загрузиться, но recv возвращает именно сколько байт скопировано, а скопировано меньше Length(buf). В результате выход из цикла и копируется не весь буфер winsock.
Решение:
1. Условие выхода из цикла ErrorCode=0, т.е. закрытие соединения, но, если посылать Connection: Keep-Alive, то сервер не закроет соединение.
2. Выходить из цикла по таймауту, но, скажем, 5 секунд - слишком много, а если сделать меньше, то большие страницы могут не прогрузиться.
3. Смотреть на Content-Length в заголовке, но не всегда сервер посылает Content-Length
Какие есть еще варианты?
Если перед циклом поставить sleep(5000), к примеру, то все работает по изначальному коду, но такие костыли использовать не очень хочется.

Примечание:
Так и не дописал модуль. Хотел лучший ответ выбрать, когда допишу, но времени уже прошло много, а времени все нет, так что выберу сейчас.
Ответы:
Так ведь данные не обязаны приходить все разом. Могут и по 300(типично 1200-1400) байт за раз приходить, считывать нужно в цикле, да ещё и учитывая возможные подвисания на случай если удалённый узел перестанет отвечать. В общем select в помощь.
Примечание №2
>3. Смотреть на Content-Length в заголовке, но не всегда сервер посылает Content-Length
Все HTTP/1.1 сервера посылают заголовок Content-Length, за исключением chunked ответов. Принимая ответы не учитывая этого, можно получить кашу вместо данных.


12 лет назад

RPI.su - самая большая русскоязычная база вопросов и ответов. Наш проект был реализован как продолжение популярного сервиса otvety.google.ru, который был закрыт и удален 30 апреля 2015 года. Мы решили воскресить полезный сервис Ответы Гугл, чтобы любой человек смог публично узнать ответ на свой вопрос у интернет сообщества.

Все вопросы, добавленные на сайт ответов Google, мы скопировали и сохранили здесь. Имена старых пользователей также отображены в том виде, в котором они существовали ранее. Только нужно заново пройти регистрацию, чтобы иметь возможность задавать вопросы, или отвечать другим.

Чтобы связаться с нами по любому вопросу О САЙТЕ (реклама, сотрудничество, отзыв о сервисе), пишите на почту [email protected]. Только все общие вопросы размещайте на сайте, на них ответ по почте не предоставляется.