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

Posted

技术标签:

【中文标题】Indy,如何知道所需缓冲区的大小?【英文标题】:Indy, How to know size of buffer needed? 【发布时间】:2011-07-08 13:24:20 【问题描述】:

我在使用 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;

那么我如何准确计算客户端发送了多少字节数据(数据包长度)?或者有人可以告诉我读取数据的正确代码吗?

【问题讨论】:

你为什么使用原始 TCP 组件?您尝试通过 TCP 进行通信的协议是什么?当提出这样的位级问题时,这是一个非常重要的问题。 【参考方案1】:

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

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

【讨论】:

如果我使用 AThread.connection.ReadStream 会怎样?我会添加更多描述【参考方案2】:

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

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;

【讨论】:

你能解释一下这行“DataSize := AThread.Connection.ReadSmallInt - 4;” 第 3 和第 4 个字节由一个 16 位网络字节序整数组成,该整数指定数据包的总大小。该长度包括前 4 个字节。因此,您必须检索长度,然后减去 4 以获得剩余有效负载的长度。

以上是关于Indy,如何知道所需缓冲区的大小?的主要内容,如果未能解决你的问题,请参考以下文章

如何动态知道 TCP 缓冲区大小

ffmpeg“低估了所需的缓冲区大小”

如何定义通道缓冲区的最佳大小? [关闭]

GetUserNameEx() 返回的缓冲区大小

与 JSON 相比,作为协议缓冲区发送时消息的大小如何减小

如何在 Winsock 中查找当前使用的 UDP 接收缓冲区大小