我最近在做一个cs结构的应用,客户端需要和服务器一直长期保持连接,且客户端无人值守,我令客户端每1分钟测试一下和服务器的连接(采用收发验证数据),当连接异常中断的时侯客户端重新发起连接。可是我发现有如下问题:
    客户端每发起一次连接,服务器端都会产生一个相应的线程来相应,但是服务端以前响应该客户端的线程并没有结束(原来的线程会一直在ReadLn处等待),也就是说服务器端的线程数量会越来越多,这样肯定是不行的,因为我的客户端和服务器一直保持连接要6个月以上。我想问的是如何让服务器根据网络的异常情况释放掉对应线程,让服务器端对每一个客户端只有一个响应的线程,而不是有多个响应的线程。谢谢回答!

解决方案 »

  1.   

    在服务程序的onexecute时间判断try   except  end
      

  2.   

    如果网络异常(比如断连)不时出现在服务器的网线上,而是出现在客户端的网线上,服务器端是检测不到异常的,还是会一直在ReadLn处等待,也就是说这个线程不会结束,用结构化异常是不能判断的!您可以试验一下。多谢您的回答。
      

  3.   

    在readln前加判断。
    if AThread.Terminated or (not AThread.Connection.Connected) then exit;TIdTcpServer最多可以连接不到2K个客户端,写过测试程序。
      

  4.   

    可以启用Sockect的KeepAlive机制,10秒内可以检测出由于网络物理中断引起的网络错误,并中断此TCP/IP连接。
    unit utils_socketc;interface
    uses IdStackConsts,IdStackWindows,IdWinSock2;const
      IOC_IN               =$80000000;
      IOC_VENDOR           =$18000000;
      SIO_KEEPALIVE_VALS   =IOC_IN or IOC_VENDOR or 4;
    type tcp_keepalive=record
        onoff:Longword;
        keepalivetime:Longword;
        keepaliveinterval:Longword;
      end;
    //设置KeepAlive用于检测线路是否中断function SetKeepALive(const SockHandle:integer):Boolean;
    implementation
    function SetKeepALive(const SockHandle:integer):Boolean;
    var
        KeepAliveIn   : tcp_keepalive;
        KeepAliveOut  : tcp_keepalive;
        Status        : Integer; 
        BytesReturned : Cardinal;
        Akeepalivetime,Akeepaliveinterval:integer; 
    begin                              
    Result:=false;
    //启用KeepALive
    KeepAliveIn.onoff:=1;
    //发送检测包间隔(2s)
    KeepAliveIn.keepalivetime:=2000;
    //回应超时(1s),默认情况下,如果出现超时,Windows将重新发送检测包,直到5次全部失败。
    KeepAliveIn.keepaliveinterval:=1000;
    Status:=WSAIoctl(SockHandle, SIO_KEEPALIVE_VALS,
                                   @KeepAliveIn,  SizeOf(KeepAliveIn),
                                   @KeepAliveOut, SizeOf(KeepAliveOut),
                                   @BytesReturned, nil, nil);
    if Status <> 0 then
       begin
         showmsgc.showNormal_msg('SetKeepAlive error','');
         exit;
       end;
     Result:=true;
    end;
    end.调用
    SetKeepALive(self.IdTCPClient.Socket.Binding.Handle);另外一个简单方法是在idtcpserver的onconnect消息中,为每个连接设置读超时,ReadLn在达到读超时后,出现一个错误,用try except可以捕捉到,然后disconnect就可以了。
      

  5.   

    while Form1.TCPClient.Connected and not ReadThread.Terminated do
      begin
        c:=Form1.TCPClient.ReadFromStack(True,-2,True);
        if c<1 then Continue;
        try
          Form1.TcpClient.ReadBuffer(F,SizeOf(F));
          Form1.TcpClient.ReadBuffer(Verify,SizeOf(Verify));
          ....
        except
          Synchronize(DisplayError);//由于没有得到数据,每次都显示"线程执行错误!!!"
        end;
      end
    ...
    procedure TReadThread.DisplayError;
    begin
      Form1.StatusBar.Panels.Items[2].Text:='线程执行错误!!!';
    end;ReadFromStack 检测有没有数据到达,并返回字节数
    但不知为何报read timeout?