天天看点

Delphi TIdTCPClient的使用问题

开发环境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;
           
上一篇: 关于object类
下一篇: 测试的流程

继续阅读