【问题标题】:Reading unknown amount of bytes from IdTCPServer connection in delphi从delphi中的IdTCPServer连接读取未知数量的字节
【发布时间】:2019-02-08 19:57:13
【问题描述】:

我正在设置一个客户端/服务器程序以在我的应用程序中发送和接收未知数量的字节。如何在我的程序中接收未知的缓冲区大小?

我将我的数据传递给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;

在服务器端,连接后,通过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。数据包很好,发送也很好。但是在服务器端提出了问题。

【问题讨论】:

    标签: delphi indy10 delphi-10.2-tokyo


    【解决方案1】:

    TIdBytes_Var 的第一个字节决定了数据包的大小,并因其他条件而变化。

    所以,然后简单地先读取 1 个字节,然后读取它说的附加字节数,例如:

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

    我会注意包的大小不超过 1024 字节。

    单个字节不能超过 255,因此您的最大数据包大小为 256,包括大小字节。

    在我将第一个数据包从客户端发送到服务器后,在调试模式下出现问题并接收: “带有消息'''的引发的异常类EConvertError不是有效的浮点值”

    您显示的代码不可能引发该异常。

    更新

    这是我的最小代码

    现在看到您的代码,我可以看到,尽管您之前声称,您的数据包的 第一个 字节不是数据包大小,它始终是 $01。实际上,数据包中根本没有存储数据包大小。 2nd字节包含了数据包中存储的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;
    

    【讨论】:

    • 感谢 Remy Lebeau。单个字节不能超过255,所以……这个字节算我的记录。
    • 我正在尝试读取第一个字节,但问题再次出现。在接收方从发送方发送数据包后立即出现此问题。 IdTCPServerExecute 不执行,只有连接丢失,在调试模式下会出现此错误。我定义了一个字节并尝试通过仅添加以下行从缓冲区中读取它:tbyte:= AContext.Connection.IOHandler.ReadByte;.
    • 那你做错了。请edit your question 包含一个minimal reproducible example,显示准确客户端如何准备和发送TIdBytes_Var,以及准确服务器如何尝试读取byte_buffer。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    • 2013-11-09
    相关资源
    最近更新 更多