Indy,如何知道所需的缓冲区大小?

时间:2011-03-04 04:22:02

标签: delphi buffer indy

使用Indy( idTCPServer 组件)读取客户端发送的数据时出现问题,数据本身是十六进制格式,所以我不能使用 AThread.Connection.ReadLn( ); 为此...

这是我的客户

发送的样本数据
24 24 00 11 12 34 56 FF FF FF FF 50 00 8B 9B 0D 0A

24 24 00 13 12 34 56 FF FF FF FF 90 02 00 0A 8F D4 0D 0A

PS :它是以十六进制为单位的字节数据(数据长度可能会因命令而异,最大 160字节),因为$ 00已转换为null,因此无法获取字符串表示形式(这意味着我不能使用ReadLn)

这是我的示例代码

procedure TfrmMain.IdTCPServerExecute(AThread: TIdPeerThread);
var
  Msg : Array[0..255] of Byte;
begin      
  AThread.connection.ReadBuffer(Msg,SizeOf(Msg));
  AThread.connection.WriteBuffer(Msg,MsgSize,true);
end;

如果客户端不发送255字节数据,此代码将无法工作,而在我的情况下,数据长度可以变化,我试过这个,但没有响应输出

procedure TfrmMain.IdTCPServerExecute(AThread: TIdPeerThread);
var
  Msg : Array of Byte;
  MsgSize : integer;
begin  
  MsgSize := AThread.connection.ReadInteger; //doesn't actually get packet length?
  SetLength(Msg, MsgSize);    
  AThread.connection.ReadBuffer(Msg,MsgSize);
  AThread.connection.WriteBuffer(Msg,MsgSize,true);
end;

那么我究竟能算出客户端发送的字节数据(包长度)究竟是多少?或者有人能告诉我正确的代码来读取数据吗?

2 个答案:

答案 0 :(得分:4)

简单的答案是:你不能。 TCP是协议,因此没有消息的概念。数据以块的形式接收,块的大小可能(并且将)与实际发送的缓冲区不同(网络堆栈可以随意切片或合并流)。
您可以在TCP之上构建消息协议,例如通过“大小字段”开始传输和每个后续消息,然后只等待所需的字节;您仍然需要检查收到的实际尺寸,并重新阅读其余部分(如果适用)。

重点是:TCP世界中的数据包长度 nothing 与已发送消息的长度有关。
所有TIdTCPConnection方法背后的Read所做的是:
从网络堆栈中读取所有可用数据,将其附加到内部输入缓冲区并从缓冲区的开头返回所请求的 N 字节(如果可用)(等待下一个块)如果没有)。

答案 1 :(得分:3)

您显示的数据中的第3个和第4个字节指定了要发送的数据的总大小。您接近尝试ReadInteger(),但您使用它的方式包括第1和第2个字节,这是错误的。试试这个:

procedure TfrmMain.IdTCPServerExecute(AThread: TIdPeerThread);
var
  Unknown: Smallint; // maybe a msg type?
  DataSize: Smallint;
  Data: Array of Byte;
begin
  Unknown := AThread.Connection.ReadSmallInt;
  DataSize := AThread.Connection.ReadSmallInt - 4;
  SetLength(Data, DataSize);
  AThread.Connection.ReadBuffer(Data[0], DataSize);
  //...
end;