首先感谢你的回答,等了好多天啊。
不是网络的问题,因为以前的一个版本软件运行的很好,一天一夜也不会延迟。
以前的版本是vb写的用的winsck控件,运行的不错,现在换成delphi用了
Indy控件,我每次是用readln读一行,是不是因为没有把缓冲区读完呢?
现在我把winsck控件弄到delphi里了,写好后运行一下看看是否延迟。
另外想问一下,delphi的子线程中用到indy控件时,是否也要使用sychonize把它
包含呢?Indy不是号称线程安全吗?

解决方案 »

  1.   

    Indy我用的比较少。我一般用的是TTcpClient 和 TTCpServer,  这2个Delphi自带的控件。接收数据 一般是 命令头 + 数据,这样的结构。先接收命令头,判断是否为有效协议,然后才是接收数据,接收数据要注意,最后接收的数据不一定正好是缓冲区的大小。
    比如:
    //Msg.dwLen = 1028;  需要接收数据长度
    const 
      BuffLen =  512;
    var
      Buffer: array [0..511] of byte;
      iLeft: Integer;  //剩余长度
      iTotal: integer; //接收数据总长度
      iRcv: integer;   //接收数据长度
    begin 
      iLeft := 0;
      iTotal := 0;
      while iTotal < Msg.dwLen do
      begin 
        iLeft := Msg.dwLen - iTotal;   //如果剩余数据长度小于缓冲区长度,则按剩余数据长度接收。否则按缓冲区长度接收
        if iLeft < BufferLen then   
          ilen := Rcv(Buffer, iLeft)
        else 
          ilen := Rcv(Buffer, BufferLen);
        
        if ilen = -1 then 
        begin 
           closesocket(s);
           break; 
        end;//如果有错误发生,则退出接收。并关闭socket    itotal := itotal + ilen;
      end;
    end;
    VCL 控件 在线程 最好使用Sychonize() 来调用它。
      

  2.   

    TTcpClient可以工作于非阻塞模式吗?我把它设置为非阻塞后,连接就不成功了?有什么好建议吗?
      

  3.   

    TTcpClient 可以用于非阻塞模式,不过,得要用异步选择去操作。示例代码如下所示 ://socket模型使用 异步选择uses WinSock;//定义消息
    const
      WM_SOCKET = WM_USER + 2034;
    //消息处理
      procedure OnSocket(var Msg: TMessage); message WM_SOCKET;//sokcet 事件处理
      function OnFDRead(const s: TSocket): Boolean;
      function OnFDClose(const s: TSocket): Boolean;
      function InitSocket(const s: TSocket): Boolean;
      function OnRcv(const s: TSocket): Boolea;implementationfunction InitSocket(const s: TSocket): Boolean;
    begin
      //监测socket的事件,详见MSDN
      Result := (0 = WSAAsyncSelect(s, Handle, WM_SOCKET, FD_READ or FD_CLOSE)) ;
    end;
    function OnFDClose(const s: TSocket): Boolean;
    begin
     Result := closesocket(s) = 0;
    end;function OnFDRead(const s: TSocket): Boolean;
    var
      iRcv: integer;
      protocol: TProtocol;  //协议结构体。
    begin
       //读取数据
       Zeromemory(@protocol, sizeof(TProtocol));
       iRcv := recv(s, protocol, sizeof(TProtocol), 0);
       if (-1 = iRcv) and (WSAGetLastError = WSAECONNRESET) then
       begin
          onFDClose(s);
          Exit;
       end;  //如果发生错误,则关闭socket    case protocol.dwCommand of
         ....
       end; //命令判别   OnRcv(s);
    end;function OnRcv(const s: TSocket): boolean;
    const
      BufLen = 512;
    var
      ilen: Integer;
      iTotal: Integer;
      Buffer: array [0 .. BufLen] of Byte;
      iLeft: Integer;
      //FStream: TMemoryStream; 是存放接收到数据。
    begin
      ilen := 0;
      iTotal := 0;
      while iTotal < FMsgLen do
      begin
        iLeft := FMsgLen - iTotal;
        if iLeft > BufLen then
          iLeft := BufLen;    ilen := recv(FSockt, Buffer, BufLen, 0);   //WSAEWOULDBLOCK    if (SOCKET_ERROR = iLeft) and (WSAGetLastError = WSAECONNRESET) then
        begin
          closesocket(FSockt);
          break;
        end;  //异步时,返回-1,并不一定是socket发生错误。    FStream.WriteBuffer(Buffer, ilen);
        iTotal := iTotal + ilen;
      end;  Result := iTotal = FMsgLen;
    begin 
    end;
      

  4.   


    procedure OnSocket(var Msg: TMessage); 
    var
      sockt: TSocket;
    begin
      sockt := Msg.WParam;  if WSAGetAsyncError(Msg.LParam) <> 0 then
      begin
        OnFDClose(sockt);
        Exit;
      end;   //socket是否有错误发生。  case WSAGetSelectEvent(Msg.LParam) of
        FD_READ:
          OnFDRead(sockt);
        FD_CLOSE:
          OnFDClose(sockt);
      end;  //判断此socket的事件。
    以上代码需要写在TForm对象中。
      

  5.   


    function OnRcv(const s: TSocket): boolean;
    const 
      BufLen = 512;
    var  
      ilen: Integer;   
      iTotal: Integer;   
      Buffer: array [0 .. BufLen - 1 ] of Byte;