Indy TCPServer не получает все пакеты от TCPClient при слишком частой отправке пакетов
У меня проблема с подключением Indy TCP. Я использую Turbo Delphi 2006 с Indy 10.
Я хочу отправить несколько пакетов TCP с данным idTCPClient idTCPServer.
Это прекрасно работает, когда я хочу отправить только один пакет, или я вставляю команду sleep(100) между двумя вызовами функции. Но если я вызываю эту функцию слишком часто, она не вызывает onExecute сервера каждый раз.
Мой код для отправки:
procedure SendData(var data: TIdBytes) ;
begin
FormMain.IdTCPClient.Connect ;
FormMain.IdTCPClient.Socket.Write(data);
FormMain.IdTCPClient.Disconnect ;
end ;
Я вызываю эту функцию несколько раз (5-10 раз в a во-вторых), и хочу обработать все эти пакеты в моем серверном приложении:
procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext);
var
data: TIdBytes ;
begin
AContext.Connection.IOHandler.ReadBytes(data, 4, false)
// processing data
end
Заранее благодарю вас за ответы!
1 ответ:
Каждый раз, когда вы вызываете
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;
Comments