ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > Программирование > С/С++, C#, Delphi, .NET, Asm
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

[Delphi] Задержка в WinSock между send() и recv()
  #1  
Старый 29.09.2009, 04:22
Аватар для GlooK
GlooK
Участник форума
Регистрация: 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..
 
Ответить с цитированием

  #2  
Старый 29.09.2009, 09:08
Аватар для slesh
slesh
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме:
3288241

Репутация: 3349


Отправить сообщение для slesh с помощью ICQ
По умолчанию

Так это дело даже не в сети. потому что в винде идет полюбому буферизация и если неуспел считать то уже будут склеиваться данные.
Вообще всё зависит от реализации сервера.
Типичные сервера первым пакетом шлют хидер а вторым данные. А нетепичные сервера - шлют сразу всё вместе или хидер разбивают.
по этому когда шлеш данные то вписывай поле
Connection: Close
Как тока сделал send то в цикле гоняй recv пока будут идти данные.
Как только он вернул <=0 то выходи из цикла.
Также желательно замутить таймаут на recv чтобы небыло подвисаний на сверхглючных серваках (вернее самописном вебсервере где он не разрывает соединение потому что не воспринимает Connection: Close)
 
Ответить с цитированием

  #3  
Старый 29.09.2009, 14:52
Аватар для GlooK
GlooK
Участник форума
Регистрация: 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;
И если реализовывать таймаут, то обязательно переводить сокеты в неблокирующий режим?

Буду рад примерам из собственных реализаций
 
Ответить с цитированием

  #4  
Старый 29.09.2009, 15:03
Аватар для slesh
slesh
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме:
3288241

Репутация: 3349


Отправить сообщение для slesh с помощью ICQ
По умолчанию

наоборот строки поставь
Код:
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
 
Ответить с цитированием

  #5  
Старый 29.09.2009, 15:18
Аватар для GlooK
GlooK
Участник форума
Регистрация: 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.
 
Ответить с цитированием

  #6  
Старый 29.09.2009, 15:27
Аватар для slesh
slesh
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме:
3288241

Репутация: 3349


Отправить сообщение для slesh с помощью ICQ
По умолчанию

вообще покажи полностью исходник.
Судя по тому что ты показывал у тебя дискриптор сокета - глобальная переменная.
Вот он и затирается скорее всего.
 
Ответить с цитированием

  #7  
Старый 29.09.2009, 15:39
Аватар для GlooK
GlooK
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме:
2310282

Репутация: 149
По умолчанию

Цитата:
Сообщение от slesh  
вообще покажи полностью исходник.
Судя по тому что ты показывал у тебя дискриптор сокета - глобальная переменная.
Вот он и затирается скорее всего.
Сорцы отправил в личку.
А сокет действительно глобальная переменная
 
Ответить с цитированием

  #8  
Старый 29.09.2009, 15:48
Аватар для slesh
slesh
Reservists Of Antichat - Level 6
Регистрация: 05.03.2007
Сообщений: 1,985
Провел на форуме:
3288241

Репутация: 3349


Отправить сообщение для slesh с помощью ICQ
По умолчанию

советую глянуть исходнки моего httpsender'a там всё нормально работало.
И там уже есть готовая функция для отправки и получения данных
 
Ответить с цитированием

  #9  
Старый 29.09.2009, 15:53
Аватар для GlooK
GlooK
Участник форума
Регистрация: 20.04.2007
Сообщений: 174
Провел на форуме:
2310282

Репутация: 149
По умолчанию

Цитата:
Сообщение от slesh  
советую глянуть исходнки моего httpsender'a там всё нормально работало.
И там уже есть готовая функция для отправки и получения данных
Спасибо за советы. Уже качаю
 
Ответить с цитированием

  #10  
Старый 29.09.2009, 18:26
Аватар для GlooK
GlooK
Участник форума
Регистрация: 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)
 


Быстрый переход




ANTICHAT.XYZ