Возникла проблемка, которую я решил, но решение думаю не совсем верное. Конструкция указанная в примере работала нормально, до тех пор пока на запрос не возвращалось коротких ответов. Но когда ответ приходит небольшой (например, 400 Bad Request, где одни хидеры), то возникает косяк. Заключает он в том, что ответ не успевает приняться и следующий ответ от сервера включает в себя два(!) ответа. В ответе идут хидеры 400 бед реквеста и 200 ок вместе. Это не позволяет нормально анализировать принятые данные. Код Code: function fWSWrite(hInput: string):string; var hOutput: array[0..5000] of char; begin Send(hSocket, hInput[1], length(hInput), 0); FillChar(hOutput, SizeOf(hOutput), 0); Recv(hSocket, hOutput, 5000, 0); result := hOutput; end; Решение нашел такое: Code: function fWSWrite(hInput: string):string; var hOutput: array[0..5000] of char; begin Send(hSocket, hInput[1], length(hInput), 0); sleep(1000); FillChar(hOutput, SizeOf(hOutput), 0); Recv(hSocket, hOutput, 5000, 0); result := hOutput; end; Но считаю, что это не совсем корректно. В MSDN ничего о задержки при отправке/приеме не увидел. Подскажите, пожалуйста, верное решение? UPD: Нашел вариант по лучше (через select): Code: function fWSWrite(hInput: string):string; var hOutput: string; hArray: array[0..5000] of char; rdfs: tfdset; tmout: timeval; ievnt: integer; cntread: integer; begin cntread := 1; Send(hSocket, hInput[1], length(hInput), 0); FillChar(hArray, SizeOf(hArray), 0); while (cntread > 0) do begin FD_ZERO(rdfs); FD_SET(hSocket, rdfs); tmout.tv_sec := 0; tmout.tv_usec := 500000; ievnt := select(0, @rdfs, nil, nil, @tmout); if (ievnt <= 0) then break; cntread := Recv(hSocket, hArray, 5000, 0); hOutput := hOutput + copy(hArray, 1, cntread); end; result := hOutput; end;
Так это дело даже не в сети. потому что в винде идет полюбому буферизация и если неуспел считать то уже будут склеиваться данные. Вообще всё зависит от реализации сервера. Типичные сервера первым пакетом шлют хидер а вторым данные. А нетепичные сервера - шлют сразу всё вместе или хидер разбивают. по этому когда шлеш данные то вписывай поле Connection: Close Как тока сделал send то в цикле гоняй recv пока будут идти данные. Как только он вернул <=0 то выходи из цикла. Также желательно замутить таймаут на recv чтобы небыло подвисаний на сверхглючных серваках (вернее самописном вебсервере где он не разрывает соединение потому что не воспринимает Connection: Close)
Про Connection: Close не знал. Спасибо. Просто я делал эти запросы через браузер, и он этого не вписывал. Тогда код получается такой (без таймаута)? Code: function fWSWrite(hInput: string):string; var hOutput: string; hArray: array[0..5000] of char; cntread: integer; begin cntread := 1; Send(hSocket, hInput[1], length(hInput), 0); FillChar(hArray, SizeOf(hArray), 0); while (cntread > 0) do begin cntread := Recv(hSocket, hArray, 5000, 0); hOutput := hOutput + copy(hArray, 1, cntread); end; result := hOutput; end; И если реализовывать таймаут, то обязательно переводить сокеты в неблокирующий режим? Буду рад примерам из собственных реализаций
наоборот строки поставь Code: while (true) do begin cntread := Recv(hSocket, hArray, 5000, 0); if (cntread > 0) then hOutput := hOutput + copy(hArray, 1, cntread) else break; end; end; насчет таймаутов я в своей статейке про юзанье winsock описывал как это делать. и там не нужно было переводить в неблокируемый режим. там юзалось setsockopt
Не получается. Сейчас все запросы сразу посылаются. При снифе идет сразу четыре запроса GET. Ответ только на первом. Вот пример отправляемого запроса: Code: GET url HTTP/1.1 Host: url User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ru,en-us;q=0.7,en;q=0.3 Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: close Referer: url P.S. Во всех запросах изменил Connection: keep-alive на Connection: close.
вообще покажи полностью исходник. Судя по тому что ты показывал у тебя дискриптор сокета - глобальная переменная. Вот он и затирается скорее всего.
советую глянуть исходнки моего httpsender'a там всё нормально работало. И там уже есть готовая функция для отправки и получения данных
HTTP Sender архив битый. Перезалей плиз. Кстати, при приеме данных, максимальное число принятых данных cntread не превышает 2048. Т.е. текст обрезается. Code: while (true) do begin cntread := Recv(hSocket, hArray, 5000, 0); if (cntread > 0) then hOutput := hOutput + copy(hArray, 1, cntread) else break; end; end; Нашел правильное решение. Думаю уже конечное. Code: function fWSWrite(hInput: string):string; var hOutput: string; hArray: array[0..5000] of char; iRead: integer; begin hOutput := ''; Send(hSocket, hInput[1], length(hInput), 0); FillChar(hArray, SizeOf(hArray), 0); while (TRUE) do begin iRead := Recv(hSocket, hArray, 5000, 0); if (iRead > 0) then hOutput := hOutput + copy(hArray, 1, iRead); [B]if (iRead < 2048) then break;[/B] end; result := hOutput; end; Только вот вопрос: почему 2048? P.S. Среда Turbo Delphi Lite (Portable)