Каждый раз, когда вы вызываете Connect()
, вы создаете новое соединение, и TIdTCPServer
запускает новый поток для обработки этого соединения (если вы не включили пул потоков, то есть). Это то, что вы действительно хотите? Было бы более эффективно, если бы клиент оставил соединение открытым на некоторое время и максимально использовал существующее соединение. Разъединяйте соединение только тогда, когда оно вам действительно не нужно, например, когда оно простаивает некоторое время. Установление нового соединения - дорогостоящая операция на обоих концах, поэтому вы должны максимально сократить эти издержки.
На стороне клиента, когда вы вызываете Write(data)
, он отправит весь TIdBytes
, но вы не отправляете длину этого TIdBytes
на сервер, поэтому он знает, сколько байтов ожидать. TIdIOHandler.Write(TIdBytes)
не делает это для вас, вы должны сделать это вручную.
На стороне сервера вы говорите ReadBytes()
читать только 4 байта за раз. После каждого блока из 4 байтов вы выходите из обработчика события OnExecute
и ожидаете его повторного вызова для чтения следующего блока из 4 байтов. Если длина клиентского источника TIdBytes
не кратна 4, ReadBytes()
вызовет исключение (в результате чего сервер отключит соединение), когда он попытается прочитать последний блок клиента, который составляет менее 4 байтов, поэтому код вашего сервера не получит этот блок.
Попробуйте вместо этого:
procedure SendData(var data: TIdBytes) ;
begin
FormMain.IdTCPClient.Connect;
try
FormMain.IdTCPClient.IOHandler.Write(Longint(Length(data)));
FormMain.IdTCPClient.IOHandler.Write(data);
finally
FormMain.IdTCPClient.Disconnect;
end;
end;
procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext);
var
data: TIdBytes;
begin
with AContext.Connection.IOHandler do
ReadBytes(data, ReadLongint, false);
// process data
end;
С учетом вышесказанного, если изменение кода клиента для отправки длины TIdBytes
по каким-либо причинам невозможно, используйте вместо этого код сервера:
procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext);
var
LBytes: Integer;
data: TIdBytes;
begin
// read until disconnected. returns -1 on timeout, 0 on disconnect
repeat until AContext.Connection.IOHandler.ReadFromSource(False, 250, False) = 0;
AContext.Connection.IOHandler.InputBuffer.ExtractToBytes(data);
// process data
end;
Или:
procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext);
var
strm: TMemoryStream;
data: TIdBytes;
begin
strm := TMemoryStream.Create;
try
// read until disconnected
AContext.Connection.IOHandler.ReadStream(strm, -1, True);
strm.Position := 0;
ReadTIdBytesFromStream(strm, data, strm.Size);
finally
strm.Free;
end;
// process data
end;
Или:
procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext);
var
strm: TMemoryStream;
begin
strm := TMemoryStream.Create;
try
// read until disconnected
AContext.Connection.IOHandler.ReadStream(strm, -1, True);
// process strm.Memory up to strm.Size bytes
finally
strm.Free;
end;
end;