Я пишу клиент-серверное приложение с использованием инди-компонентов TIdTCPClient / TIdTcpServer в Delphi.
Передача данных обычно работает нормально, но часто я читаю неверные данные с сервера; Я получаю ответы на предыдущие запросы, а не на текущие.
Во время отладки оба приложения работают локально, поэтому данные не могут быть потеряны во время передачи.
Таймауты составляют 1000-3000 мсек, этого достаточно, чтобы избежать отправки второго запроса до получения ответа на первый.
Я использую простой формат данных: первые 4 байта - это длина пакета данных, остальные - двоичные данные этой длины.
Код на стороне сервера (упрощен для отправки только строк; я также использую двоичные буферы таким же образом, но этот код проще понять и проверить):
Var
lng: LongInt;
ib: TIdBytes;
begin
// Prepare data to send:
lng:=length(s);// s is an AnsiString to be sent
SetLength(ib,lng+4);
Move(lng,ib[0],4);
Move(s[1],ib[4],length(s));
// Send:
AContext.Connection.IOHandler.WriteDirect(ib);
end;
Код на стороне клиента для отправки запроса такой же (вызов TIdTcpClient.IOHandler.WriteDirect () в последней строке). Клиентский код для чтения ответа сервера:
Var
ib: TIdBytes;
size,done,lng: LongInt;
begin
Result:=false;
// answer length:
try
SetLength(ib,0);
tcp.IOHandler.ReadBytes(ib,4,false);
Move(ib[0],size,4);
if length(ib)<0 then Exit;// wrong data
except
on E: Exception do;// code skipped
end;
// read answer body:
done:=0;
b.Clear;// b is my buffer, TStream descendant
while done<size do
begin
lng:=Min(size-done,MaxBlockSize);
// read:
SetLength(ib,0);// to be sure
tcp.IOHandler.ReadBytes(ib,lng,false);
if length(ib)=0 then Exit;// error reading
// append my buffer:
b.Wr(ib[0],length(ib));
// progress:
Inc(done,length(ib));
end;
end;
Порядок обмена данными:
Клиент отправляет запрос на сервер,
Сервер читает запрос и отправляет ответ клиенту,
Клиент читает ответ.
На шаге 3 появляются неверные данные.
Может я что то вообще не так делаю?
Я пробовал ReadBytes () прямо перед отправкой запроса на сервер для очистки входящего буфера, но это тоже не помогает, как и многие другие вещи, которые я пробовал ...
Теперь у меня просто нет идей :(
TIdTCPServer
- это многопоточный компонент. Каждый клиент работает в собственном рабочем потоке, а не в основном потоке. СобытиеOnExecute
запускается в контексте этих рабочих потоков. Таким образом, он МОЖЕТ обрабатывать несколько клиентов параллельно, и поэтому вы должны убедиться, что ваш код обработчика событий является потокобезопасным. - person Remy Lebeau   schedule 16.01.2015