Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей.
Здесь обсуждаются безопасность, программирование, технологии и многое другое.
Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
 |
[Delphi] Задержка в WinSock между send() и recv() |

29.09.2009, 04:22
|
|
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме: 2310282
Репутация:
149
|
|
[Delphi] Задержка в WinSock между send() и recv()
Возникла проблемка, которую я решил, но решение думаю не совсем верное.
Конструкция указанная в примере работала нормально,
до тех пор пока на запрос не возвращалось коротких ответов.
Но когда ответ приходит небольшой (например, 400 Bad Request, где одни хидеры), то возникает косяк.
Заключает он в том, что ответ не успевает приняться и следующий ответ от сервера включает в себя два(!) ответа.
В ответе идут хидеры 400 бед реквеста и 200 ок вместе.
Это не позволяет нормально анализировать принятые данные.
Код
Код:
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;
Решение нашел такое:
Код:
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):
Код:
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;
Последний раз редактировалось GlooK; 29.09.2009 в 06:06..
|
|
|

29.09.2009, 09:08
|
|
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме: 3288241
Репутация:
3349
|
|
Так это дело даже не в сети. потому что в винде идет полюбому буферизация и если неуспел считать то уже будут склеиваться данные.
Вообще всё зависит от реализации сервера.
Типичные сервера первым пакетом шлют хидер а вторым данные. А нетепичные сервера - шлют сразу всё вместе или хидер разбивают.
по этому когда шлеш данные то вписывай поле
Connection: Close
Как тока сделал send то в цикле гоняй recv пока будут идти данные.
Как только он вернул <=0 то выходи из цикла.
Также желательно замутить таймаут на recv чтобы небыло подвисаний на сверхглючных серваках (вернее самописном вебсервере где он не разрывает соединение потому что не воспринимает Connection: Close)
|
|
|

29.09.2009, 14:52
|
|
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме: 2310282
Репутация:
149
|
|
Про Connection: Close не знал. Спасибо.
Просто я делал эти запросы через браузер, и он этого не вписывал.
Тогда код получается такой (без таймаута)?
Код:
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;
И если реализовывать таймаут, то обязательно переводить сокеты в неблокирующий режим?
Буду рад примерам из собственных реализаций 
|
|
|

29.09.2009, 15:03
|
|
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме: 3288241
Репутация:
3349
|
|
наоборот строки поставь
Код:
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
|
|
|

29.09.2009, 15:18
|
|
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме: 2310282
Репутация:
149
|
|
Не получается.
Сейчас все запросы сразу посылаются. При снифе идет сразу четыре запроса GET.
Ответ только на первом.
Вот пример отправляемого запроса:
Код:
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.
|
|
|

29.09.2009, 15:27
|
|
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме: 3288241
Репутация:
3349
|
|
вообще покажи полностью исходник.
Судя по тому что ты показывал у тебя дискриптор сокета - глобальная переменная.
Вот он и затирается скорее всего.
|
|
|

29.09.2009, 15:39
|
|
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме: 2310282
Репутация:
149
|
|
Сообщение от slesh
вообще покажи полностью исходник.
Судя по тому что ты показывал у тебя дискриптор сокета - глобальная переменная.
Вот он и затирается скорее всего.
Сорцы отправил в личку.
А сокет действительно глобальная переменная 
|
|
|

29.09.2009, 15:48
|
|
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме: 3288241
Репутация:
3349
|
|
советую глянуть исходнки моего httpsender'a там всё нормально работало.
И там уже есть готовая функция для отправки и получения данных
|
|
|

29.09.2009, 15:53
|
|
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме: 2310282
Репутация:
149
|
|
Сообщение от slesh
советую глянуть исходнки моего httpsender'a там всё нормально работало.
И там уже есть готовая функция для отправки и получения данных
Спасибо за советы. Уже качаю 
|
|
|

29.09.2009, 18:26
|
|
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме: 2310282
Репутация:
149
|
|
HTTP Sender архив битый. Перезалей плиз.
Кстати, при приеме данных, максимальное число принятых данных cntread не превышает 2048. Т.е. текст обрезается.
Код:
while (true) do
begin
cntread := Recv(hSocket, hArray, 5000, 0);
if (cntread > 0) then hOutput := hOutput + copy(hArray, 1, cntread) else break;
end;
end;
Нашел правильное решение. Думаю уже конечное.
Код:
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);
if (iRead < 2048) then break;
end;
result := hOutput;
end;
Только вот вопрос: почему 2048?
P.S. Среда Turbo Delphi Lite (Portable)
|
|
|
|
 |
Похожие темы
|
| Тема |
Автор |
Раздел |
Ответов |
Последнее сообщение |
|
Секретные Коды
|
_-[A.M.D]HiM@S-_ |
Сотовый фрикинг |
98 |
09.06.2010 16:01 |
|
Клиент-сервер на WinSock
|
--StraNger-- |
Авторские статьи |
1 |
21.04.2009 11:43 |
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|