Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Проблема в Сокетах. Пересылка больших объемов ин


Автор: BigMazy 10.11.2004, 01:07
Доброго времени суток!
Возникла проблема которую мне необходимо решить
Имеется программа сервер. Я пишу свою программу клиента
Сервер на запросы клиента может отправлять ответы большого размера.

Естественно эти ответы отправляются по сокетному потоку порциями, которые необходимо склеить
Проблема состоит в следующем - эти порции приходят с задержками и клиент не успевает
получить все порции и считывает 0 байт, завершая прием.
Получается, что мне необходимо ставить WaitForData (ждать определенное время) на каждый проход
цикла по склеиванию полученных порций. Но тогда, обязательно и всегда будет весомая задержка в самом конце
работы цикла, когда все данные получены и серверу нечего уже отправлять.Получается, что при получении
данных всегда будет срабатывать задержка.

Как избавится от задержки в конце работы цикла?

Вот код процедуры получения данных, где ожидается только начало получения информации. Эта функция
в реальных услових работает не корректно, так как сервер не успевает отправить все порции данных.
Что делать ? Реально нужна Ваша помощь.
Может предложите свой вариант решения

Код
function ReadLongInfo(SocketStream: TWinSocketStream; ClientSocket: TClientSocket;var pData: pChar):byte;
var
pBuffer: pChar;
size_Receive: cardinal;
size_count: cardinal;
size: cardinal;
F: textFile;
A: TASyncStyles;
begin
result:=0;
pBuffer:=nil;
//Вот ждем когда начнется передача
if SocketStream.WaitForData(30000)=false
then
begin
 result:=1;
 exit;
end;
size_count:=0;
// Цикл склеиваения
repeat
 size_Receive:=ClientSocket.Socket.ReceiveLength;
 ReAllocMem(pBuffer,size_Receive);
 if size_Receive<>0
 then
 begin
 size:=SocketStream.Read(pBuffer^,size_Receive);
 size_count:=size_count+size;
 ReAllocMem(pBuffer,size);
 ReAllocMem(pData,size_count);
 MoveMemory(pData+size_count-size,pBuffer,size);
 fillMemory(pBuffer,size,0);
 end;
until size_receive=0;
// Конец цикла
freeMem(pBuffer);
end;

Автор: p0s0l 10.11.2004, 15:28
Можно упростить так:
Код
// Цикл склеиваения
repeat
 size_Receive:=ClientSocket.Socket.ReceiveLength;
 if size_Receive<>0
 then
 begin
 ReAllocMem(pData,size_count + size_Receive);
 size:=SocketStream.Read((pData+size_count-size_Receive)^ ,size_Receive);
 size_count:=size_count+size;
 end;
until size_receive=0;
Только если у тебя большие объёмы данных, то эти ReAllocMem'ы будут тормозить, т.к. это фактически может вылится в: выделение нового куска памяти, копирование инфы из старого куска, освобождение старой памяти...
Поэтому лучше либо:
1)перед посылкой данных сервер должен выслать размер передаваемых данных - выделяй сразу буфер такого размера
2)пиши получаемые данные в файл
3)вместо ReAllocMem делай GetMem, и запоминай адрес каждого буфера в массиве...

Автор: BigMazy 11.11.2004, 10:05
Благодарю !

Автор: BigMazy 11.11.2004, 10:26
Дело в том, что Сервер нанисан не мною, есть только exe-ник
Поэтому размер передаваемых данных включить в ответ сервера не получится.
Каким образом мне узнать, что сервер закончил передавать данные ?
Если использовать для этого размер полученного куска (если 0 - то конец),
то возникает ошибка, когда очередной кусок еще не отправлен, а мой
цикл уже определяет, что размер полученных данных =0, и следовательно, конец.
Пока я нашел решение просто в каждый проход цикла ставить waitForData

/|/ Цикл склеиваения
repeat
SocketStream.WaitForData(100);
size_Receive:=ClientSocket.Socket.ReceiveLength;
if size_Receive<>0
then
begin
ReAllocMem(pData,size_count + size_Receive);
size:=SocketStream.Read((pData+size_count-size_Receive)^ ,size_Receive);
size_count:=size_count+size;
end;
until size_receive=0;
Но такой способ будет давать обязательную задержку в конце приема даных, когда данные не подаются
и поток ждет определенное время.
Можно ли еще каким-то образом определить конец передачи данных.

Автор: p0s0l 11.11.2004, 16:39
Какие данные передаёт сервер (графуку, звук, текст или что еще ) ?
Формат известен ?
Всё равно либо должен идти вначале заголовок, из которого можно узнать длину, либо в конце завершающий сигнал должен быть...

Автор: BigMazy 13.11.2004, 10:35
Большое спасибо за помощь !
Там передаются такстовые скрипты, в виде набора макрокоманд.
В конце каждого скрипта идет команда END, по которой и можно определить
конец передачи.


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)