开发环境Delphi10.3.3
使用TIdTCPClient写了一个客户端小例子,使用网络调试助手作为服务端(设置接收到客户端信息会自动返回数据)。
通讯模式:短连接。客户端连接--发送---等待数据---接收---断开。此例子中客户端不知道返回信息长度是多少。
问题:由于不确定服务端返回数据多少,所以使用Socket.ReadBytes(dat,-1,False); -1:表示一直读取直到超时。本以为像ClientSocket那样有多少数据就能读到多少,结果试验了不同长度的数据,读取到的长度也不一样。1000多个字节没问题,超过2920就会出现读取不够的情况(经常在2920出问题,但也不全是)。读取结束后disconnect,再次connect就会抛出Already connected异常。
如果Socket.ReadBytes(dat,-1,False); 第二个参数设置为正数,表示要读取的字节数,如果实际返回的小于参数则会一直等待到readtimeout,然后抛出超时异常。如果大于参则读取成功。但这两种情况都是导致再次connect抛出Already connected异常。
解决Already connected异常的办法是idtcpclnt1.Socket.InputBuffer.Clear;
解决读取数据不够的办法是循环调用Socket.ReadBytes(dat,-1,False);
改进后如下:
procedure TReadThread.Execute;
var
dat:TIdBytes;
msg:AnsiString;
count:Integer;
tcpclient:TIdTCPClient;
begin
FreeOnTerminate:=true;
try
tcpclient:=TIdTCPClient.Create();
with tcpclient do
begin
Host := Form1.edtIP.Text;
Port := StrToInt(Form1.edtPort.Text);
Connect;
Form1.mmo1.Lines.Add('connected') ;
Socket.Write('阿斯蒂芬',IndyTextEncoding_OSDefault);
Form1.mmo1.Lines.Add('等待接收') ;
Socket.ReadTimeout:=1000*6;//读取超时时间
if Socket.CheckForDataOnSource(1000*60) then//等待数据60秒,有数据返回true
begin
repeat
SetLength(dat, 0);
Socket.ReadBytes(dat,-1,False);
count:=count+Length(dat);
msg:=BytesToString(dat,IndyTextEncoding_OSDefault);
Form1.mmo1.Lines.Add('数据长度:'+IntToStr(Length(dat))) ;
until (Socket.CheckForDataOnSource(500)=False);
Form1.mmo1.Lines.Add('总长度:'+IntToStr(count)) ;
end
else
begin
if Connected then
Form1.mmo1.Lines.Add('等待超时')
else
Form1.mmo1.Lines.Add('已断开连接') ;
end;
//关闭
if connected then
begin
if Socket.InputBufferIsEmpty then
Form1.mmo1.Lines.Add('true')
else
Form1.mmo1.Lines.Add('false');
Socket.InputBuffer.Clear;
DisConnect;
end;
end;
except
on E : Exception do
begin
Form1.mmo1.Lines.Add('异常:'+E.Message+'['+e.ClassName+']');
end;
end;
end;