You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 10.4中TIdTCPClient连接失败后如何自动重启TCP套接字?

Indy TIdTCPClient 断连重连与资源销毁指南

一、断连后无法重连的机制原理

  • TCP长连接特性:服务器主动断开后,若客户端处于阻塞读写状态,底层套接字可能进入半开连接状态(客户端认为连接仍有效,但服务器已断开)。
  • Indy组件逻辑:TIdTCPClient不会自动检测连接有效性,仅当读写操作触发超时、连接重置(EIdSocketError)或优雅断开(EIdConnClosedGracefully)异常时,才会标记连接失效。
  • 错误操作导致的残留:若未先执行Disconnect()就直接释放组件,或异常处理中未清理套接字资源,会导致系统残留无效套接句柄,后续重连无法绑定新资源。

二、自动重启套接字的实现方法

1. 异常驱动的重连触发

在所有读写操作的try-except块中捕获Indy专属异常,触发重连流程:

procedure TForm1.SendData(const AData: string);
begin
  try
    if IdTCPClient1.Connected then
    begin
      IdTCPClient1.IOHandler.WriteLn(AData);
      // 读取响应
      var Resp := IdTCPClient1.IOHandler.ReadLn;
      // 处理响应...
    end
    else
    begin
      ReconnectTCPClient;
    end;
  except
    on E: EIdConnClosedGracefully do
      ReconnectTCPClient;
    on E: EIdSocketError do
      ReconnectTCPClient;
    on E: Exception do
      ShowMessage('发送失败: ' + E.Message);
  end;
end;

2. 标准重连流程实现

重连时必须严格遵循断开→等待→重连的顺序,避免资源冲突:

procedure TForm1.ReconnectTCPClient;
begin
  // 强制断开现有连接,清理底层套接字
  if IdTCPClient1.Connected then
  begin
    try
      IdTCPClient1.Disconnect(True);
    except
      // 忽略断开异常,避免阻塞后续操作
    end;
  end;

  // 等待1秒,避免频繁重试导致服务器拒绝
  Sleep(1000);

  try
    IdTCPClient1.Connect;
    // 重连成功后初始化通信上下文(如登录、订阅)
    InitClientSession;
  except
    on E: Exception do
    begin
      // 重连失败,启动定时重试(比如3秒后再试)
      TimerReconnect.Interval := 3000;
      TimerReconnect.Enabled := True;
    end;
  end;
end;

3. 心跳机制主动检测连接

通过定时发送心跳包+超时检测,提前识别断连:

procedure TForm1.TimerHeartBeatTimer(Sender: TObject);
begin
  TimerHeartBeat.Enabled := False;
  try
    if IdTCPClient1.Connected then
    begin
      IdTCPClient1.IOHandler.ReadTimeout := 5000; // 设置5秒读超时
      // 发送心跳包
      IdTCPClient1.IOHandler.WriteLn('HEARTBEAT');
      // 等待服务器响应
      if IdTCPClient1.IOHandler.WaitForData(1000) then
      begin
        var Resp := IdTCPClient1.IOHandler.ReadLn;
        if Resp <> 'HEARTBEAT_ACK' then
          ReconnectTCPClient;
      end
      else
        ReconnectTCPClient;
    end
    else
      ReconnectTCPClient;
  except
    on E: Exception do
      ReconnectTCPClient;
  end;
  TimerHeartBeat.Enabled := True;
end;

三、套接字的正确销毁方式

  • 动态创建的组件:销毁前必须先断开连接,再释放实例:
procedure TForm1.DestroyTCPClient;
begin
  if Assigned(IdTCPClient1) then
  begin
    if IdTCPClient1.Connected then
    begin
      try
        IdTCPClient1.Disconnect(True);
      except
      end;
    end;
    IdTCPClient1.Free;
    IdTCPClient1 := nil;
  end;
end;
  • 线程中使用的组件:确保线程已终止后,再执行断开和释放操作,避免线程持有无效套接字资源。
  • 注意事项:禁止直接释放未断开的TIdTCPClient,否则会导致系统套接字资源泄漏,影响后续连接。

内容的提问来源于stack exchange,提问作者Johannes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 01:25:12