使用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;
那么我究竟能算出客户端发送的字节数据(包长度)究竟是多少?或者有人能告诉我正确的代码来读取数据吗?
答案 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;