Чтение неизвестного количества байтов из соединения IdTCPServer в delphi - PullRequest
0 голосов
/ 08 февраля 2019

Я настраиваю программу клиент / сервер для отправки и получения неизвестного количества байтов в моем приложении.Как получить неизвестный размер буфера в моей программе?

Я передаю свои данные в переменную TIdBytes и отправляю их с такой строкой:

IdTCPClient.IOHandler.Write(TIdBytes_Var);

Первый байт TIdBytes_Var определяет размер пакета и изменяется в зависимости от других условий.Я забочусь о том, чтобы размер пакета не превышал 1024 байта.

На стороне получателя (IdTCPServerExecute) я добавляю эту строку для чтения всех байтов:

var
  byte_buffer: TIdBytes;
begin
  AContext.Connection.IOHandler.ReadBytes(byte_buffer,-1,false); 
end;

В режиме отладки,после отправки первого пакета с клиента на сервер возникает исключение:

повышенный класс исключения EConvertError с сообщением '' 'не является допустимым значением с плавающей запятой

А в режиме работы только потеря соединения.

В чем проблема и как я могу получить все байты из входного буфера Indy?

Вот мой минимальный код:

В клиенте, создающем пакет и, наконец, устанавливающем событие, которое передается другому потоку

//create packet. Buffer_to_send is a TIdBytes variable on unit of network thread (U_network_thread).
SetLength(U_network_thread.Buffer_to_send,(6 + (tmp_ints * 12)));//set buffer lenght dynamically, tmp_ints is my record counter(shortint)
tmp_int:= 2;//tmp_int is the integer variable
U_network_thread.Buffer_to_send[0]:= $1;//header sign
U_network_thread.Buffer_to_send[1]:= tmp_ints;//tmp_ints is my record counter as short integer
while tmp_ints > 0 do
begin
  Read(My_File,tmp_rec);//read record from bin file
  Move(tmp_rec,U_network_thread.Buffer_to_send[tmp_int],12);//12 is record lenght
  tmp_int:= tmp_int + 12;   //add pointer
  dec(tmp_ints);
end;
tmp_int2:= zone_i;//integer info
Move(tmp_int2,U_network_thread.Buffer_to_send[tmp_int],4); //add info to the packet
Frq_Evt.SetEvent;   //set event to triger sending on other thread

На net_thread, после подключения к серверу и получения знака подтверждения с помощью команды ReadLn, я жду события

procedure TNetThread.Execute;
  .//create IdTCPClient1 and connect to server
  .//receive ack from server by IdTCPClient1.IOHandler.ReadLn command
  .//wait for event
  while(true) do
    if (FEvent.WaitFor(200) = wrSignaled) then//Buffer_to_send fill on main thread
    begin
      //send buff
      if sending_buf(Buffer_to_send) then
      begin
        //sending ok
      end
      else
      begin
        //sending error
      end;
    end;
  end;
end;

function TNetThread.sending_buf(T_Buffer: TIdBytes): boolean;
begin
  try
    IdTCPClient1.IOHandler.Write(T_Buffer)
    result := true;
  except
    result := false;
  end;
end;

На стороне сервера, после подключения отправляю ack sign командой WriteLn, а на IdTCPServerExecute пытаюсь сделать

procedure Tmain_form.IdTCPServerExecute(AContext: TIdContext);
var
  byte_buffer: TIdBytes;
begin
  AContext.Connection.IOHandler.ReadBytes(byte_buffer,-1,false);
  //do something else
end;

Все работает нормально, соединение прошло и серверотправить знак подтверждения клирунт.Клиент получает его и ждет события.После того, как событие происходит, клиент составляет пакет и передает его net_thread.Пакет хороший и отправка тоже.Но на стороне сервера возникает проблема.

1 Ответ

0 голосов
/ 09 февраля 2019

первый байт TIdBytes_Var определяет размер пакета и изменяется в зависимости от других условий.

Итак, сначала просто прочитайте 1 байт, а затем прочитайте, сколько дополнительных байтов он говорит, например:

AContext.Connection.IOHandler.ReadBytes(byte_buffer, AContext.Connection.IOHandler.ReadByte, false);

Я забочусь о том, чтобы размер пакета не превышал 1024 байта.

Один байт не может превышать 255, поэтому ваш максимальный размер пакета будетбыть 256, включая байт размера.

в режиме отладки после того, как я отправляю первый пакет от клиента на сервер, возникает проблема и получено: «Поднятый класс исключения EConvertError с сообщением« »недопустимзначение с плавающей запятой "

Код, который вы указали, не может вызвать это исключение.

Обновление

Здесьмой минимальный код

Видя ваш код сейчас, я вижу, что, несмотря на ваше предыдущее утверждение, первый байт вашего пакета НЕ является размером пакета, он всегда $01.На самом деле, размер пакета не сохраняется в пакете вообще. 2-й байт содержит количество 12-байтовых записей, хранящихся в пакете, и пакет имеет 6 фиксированных байтов, поэтому максимальный размер пакета на самом деле составляет 3066 байтов.

Попробуйте что-то похожееэто:

передается в другой поток

// create packet. Buffer_to_send is a TIdBytes variable on unit of network thread (U_network_thread).
SetLength(U_network_thread.Buffer_to_send, (6 + (tmp_ints * 12))); // set buffer length dynamically, tmp_ints is my record counter(shortint)
tmp_int := 2; // tmp_int is the integer variable
U_network_thread.Buffer_to_send[0] := $1; //header sign
U_network_thread.Buffer_to_send[1] := tmp_ints; // tmp_ints is my record counter as short integer
while tmp_ints > 0 do begin
  Read(My_File, tmp_rec); // read record from bin file
  Move(tmp_rec, U_network_thread.Buffer_to_send[tmp_int], 12); // 12 is record length
  Inc(tmp_int, 12); // add pointer
  Dec(tmp_ints);
end;
tmp_int2 := GStack.HostToNetwork(UInt32(zone_i)); // integer info, in network byte order
Move(tmp_int2, U_network_thread.Buffer_to_send[tmp_int], 4); // add info to the packet
Frq_Evt.SetEvent; // set event to trigger sending on other thread

procedure Tmain_form.IdTCPServerExecute(AContext: TIdContext);
var
  byte_buffer: TIdBytes;
  Header: Byte;
  Count: Word;
  Zone: Integer;
begin
  Header := AContext.Connection.IOHandler.ReadByte; // should always be $01
  Count := AContext.Connection.IOHandler.ReadByte; // record counter
  AContext.Connection.IOHandler.ReadBytes(byte_buffer, Count * 12); // records
  Zone := AContext.Connection.IOHandler.ReadInt32; // zone
  // process as needed...
end;
...