roo*_*gar 1 delphi tcp tcplistener indy
我必须设置一个tcp服务来处理一些客户端请求
所有请求都以长度为1099字节的十六进制字符串包的形式出现,并且都以开头00D0和结尾00000000
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
begin
AContext.Connection.IOHandler.ReadBytes(data, 1099, False);
RStr:='';
for I := 0 to length(data)-1 do
RStr := RStr + chr(data[i]);
if(copy(RStr,1,4)='00D0') and (copy(RStr,1091,8)='00000000') then
begin
Memo14.Lines.Add( 'Frame added to database.' );
end
else
begin
Memo14.Lines.Add( 'error invalid Frame ...' );
end;
end;
Run Code Online (Sandbox Code Playgroud)
服务器接收到1099字节数据包,但仅error invalid Frame ...显示。
我的代码有什么问题!?
PS:客户端正在向服务器连续发送数据,这意味着客户端从第三方接收数据并发送到服务器,因此可能不是从数据包的第一位开始发送数据!所以我必须先丢弃一些数据才能到达数据包00D0!
Indy BytesToString()在IdGlobal单元中具有一个功能,因此您无需将TIdBytesa string手动转换为:
RStr := BytesToString(data);
Run Code Online (Sandbox Code Playgroud)
A string通常是1索引的(除非您正在为移动设备进行编译并且不使用{$ZEROBASEDSTRINGS OFF}),所以copy(RStr,1091,8)应该使用1092而不是1091,因为您正在读取1099字节而不是1098字节:
copy(RStr,1092,8)
Run Code Online (Sandbox Code Playgroud)
但是,Indy 在单元中也具有TextStartsWith()和TextEndsWith()函数,IdGlobal因此您无需手动提取和比较子字符串:
if TextStartsWith(RStr, '00D0') and TextEndsWith(RStr, '00000000') then
Run Code Online (Sandbox Code Playgroud)
话虽如此,如果套接字数据实际上实际上是文本的而不是二进制的,则应使用TIdIOHandler.ReadString()方法而不是TIdIOHandler.ReadBytes()方法:
RStr := AContext.Connection.IOHandler.ReadString(1099);
Run Code Online (Sandbox Code Playgroud)
或者,TIdIOHandler还具有WaitFor()和ReadLn()读取分隔文本的方法,例如:
AContext.Connection.IOHandler.WaitFor('00D0');
RStr := '00D0' + AContext.Connection.IOHandler.ReadLn('00000000') + '00000000';
Run Code Online (Sandbox Code Playgroud)
要么
AContext.Connection.IOHandler.WaitFor('00D0');
RStr := '00D0' + AContext.Connection.IOHandler.WaitFor('00000000', True, True);
Run Code Online (Sandbox Code Playgroud)
最后,TIdTCPServer是一个多线程组件,其OnExecute事件是在辅助线程而不是主UI线程的上下文中触发的。因此,您必须在访问时,在界面,诸如通过RTL与主UI线程同步TThread.Queue()或TThread.Synchronize()类方法,或印的TIdNotify或TIdSync类等不好的事情可以和平时做的时候,你从主界面的外部访问UI控件发生线。
更新:在注释中,您说的是数据实际上是字节,而不是文本字符。而且,在开始读取记录之前,需要删除字节。在这种情况下,您根本不应将字节转换为a string。照原样处理字节,例如:
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var
data: TIdBytes;
b: Byte;
begin
b := AContext.Connection.IOHandler.ReadByte;
repeat
if b <> $00 then Exit;
b := AContext.Connection.IOHandler.ReadByte;
until b = $D0;
SetLength(data, 2);
data[0] = $00;
data[1] = $D0;
AContext.Connection.IOHandler.ReadBytes(data, 1097, True);
repeat
if {(PWord(@data[0])^ = $D000)}(data[0] = $00) and (data[1] = $D0)
and (PUInt32(@data[1091])^ = $00000000) then
begin
TThread.Queue(nil,
procedure
begin
Memo14.Lines.Add( 'Frame added to database.' );
end;
);
end else
begin
TThread.Queue(nil,
procedure
begin
Memo14.Lines.Add( 'error invalid Frame ...' );
end;
);
end;
AContext.Connection.IOHandler.ReadBytes(data, 1099, False);
until False;
end;
Run Code Online (Sandbox Code Playgroud)