解决TCP-socket -掉线问题的总结(转)

Delphi代码实现了多种解决"掉线"问题的策略,包括启用TCP保活定时器、自动重连机制、错误处理、以及心跳包等方法。以下是代码的格式化和详细注释说明:

// 1. TCP 保活定时器设置
type
  TCP_KeepAlive = record
    OnOff: Cardinal;          // 开启保活标志
    KeepAliveTime: Cardinal;  // 保活时间(毫秒)
    KeepAliveInterval: Cardinal; // 保活间隔(毫秒)
  end;

procedure TFrm_Client.Sck_MainConnect(Sender: TObject; Socket: TCustomWinSocket);
var
  val: TCP_KeepAlive;
  Ret: DWord;
begin
  inherited;
  try
    // 设置TCP保活定时器
    val.OnOff := 1; // 开启保活
    val.KeepAliveTime := 1000 * 60 * 60 * 24; // 24小时
    val.KeepAliveInterval := 100; // 每100毫秒发送一次保活包
    Ret := WSAIoctl(Socket.SocketHandle, IOC_IN or IOC_VENDOR or 4,
                    @val, SizeOf(val), nil, 0, @Ret, nil, nil);
  finally
    ShowInfo('已连接到服务器. TCP_KeepAlive定时器设置时间: ' + IntToStr(val.KeepAliveTime) + 'ms, 结果: ' + IntToStr(Ret));
  end;
end;

// 2. 处理错误码并触发重连机制
procedure TFrm_Client.Sck_MainError(Sender: TObject; Socket: TCustomWinSocket; 
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var
  nCode: Cardinal;
begin
  inherited;
  ShowInfo('||[Error] 出错: ' + IntToStr(ErrorCode) + '; 自动重连: ' + BoolToStr(lAskForReConnect, true));
  nCode := ErrorCode;
  ErrorCode := 0;

  // 错误码判断,若发生断线错误则尝试重连
  if (nCode = EConnAborted) or (nCode = ENetDown) or (nCode = ETimedOut) or 
     (nCode = EConnRefused) or (nCode = EHostUnReach) then 
  begin
    if lAskForReConnect and (not lInReConnecting) then
      Timer_ReConnect.Enabled := True; // 启动自动重连
    if not lInReConnecting then
    begin
      sck_Main.Active := False;
      sck_Main.Close; // 关闭连接
    end;
    ShowInfo('连接状态: ' + BoolToStr(sck_Main.Active, true) + '; 重连设置: ' + 
             BoolToStr(lAskForReConnect, true) + '; 重连状态: ' + BoolToStr(Timer_ReConnect.Enabled, true));
  end;
end;

// 3. 断开连接时自动重连
procedure TFrm_Client.Sck_MainDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  inherited;
  if (not lAskForReConnect) or (lInReConnecting) then Exit;
  Timer_ReConnect.Enabled := True; // 启动重连定时器
end;

// 4. 实现重连机制
function TFrm_Client.ReConnectServer: Boolean;
const 
  nMax = 6;  // 最大重试次数
var
  i: Integer;
begin
  Result := False;
  i := 1;
  if not lAskForReConnect then Exit;
  
  with sck_Main do
  begin
    if not lInCreatting then
    begin
      try
        // 断开连接并尝试重新连接
        sck_Main.Socket.Disconnect(sck_Main.Socket.Handle);
        sck_Main.Close;
        while (not sck_Main.Active) and (i <= nMax) do
        begin
          ShowInfo('* 尝试自动重新连接 [' + IntToStr(i) + '/' + IntToStr(nMax) + ']...');
          sck_Main.Open;
          Delay(2000);
          if not sck_Main.Active then
            Delay(1000);
          Inc(i);
        end;
      except
        on E: Exception do;
      end;
    end;
  end;
  
  lLoginOK := sck_Main.Active;
  if not lLoginOK then
  begin
    ShowInfo('已经断开服务器的连接, 正在尝试重新连接');
    lbl_Move.Caption := '已经断开连接, 正在尝试重新连接';
  end;
  Result := lLoginOK;
end;

// 5. 自动重连定时器
procedure TFrm_Client.Timer_ReconnectTimer(Sender: TObject);
begin
  inherited;
  try
    if (sck_Main.Active) or (not lAskForReConnect) then Exit;
    
    lInReConnecting := True; // 正在连接中
    Timer_ReConnect.Enabled := False; // 禁用重连定时器
    Timer_ReConnect.Enabled := (not ReConnectServer) and lAskForReConnect;
  finally
    lInReConnecting := False;
  end;
end;

// 6. 发送心跳包保持连接
procedure TFrm_Client.Timer_KeepConnectTimer(Sender: TObject);
var
  msg: _msgIdle;
begin
  inherited;
  if (not lLoginOK) or (lInReConnecting) then Exit;

  try
    if lGlobalTerminate then Exit;
    Timer_KeepConnect.Enabled := False;

    msg.Version.dwMajorVersion := frm_MDI.Version.dwMajorVersion;
    msg.Version.dwMinorVersion := frm_MDI.Version.dwMinorVersion;
    msg.nTickCount := 0;  // 设置心跳包的时间戳
    msg.nHandle := 0;     // 设置句柄
    msg.sComment := '你好!有空常联系!'; // 心跳包的内容

    if not sendMessage(sck_Main.Socket, msgTypeIdle, @msg) then 
      ShowInfo('心跳包发送失败!');
  finally
    Timer_KeepConnect.Enabled := True;
    ShowInfo('发送联系服务器消息IDLE, 结果: ' + BoolToStr(True, true));
  end;
end;

主要策略:

  1. TCP保活定时器:通过设置 KeepAliveTimeKeepAliveInterval,确保连接在无数据传输时仍能保持活跃。
  2. 错误处理:通过捕获常见的连接错误(如 10053)进行断开处理,并触发自动重连机制。
  3. 自动重连:在连接中断后,通过 Timer_ReConnect 定时器来尝试重新连接,最多重试 nMax 次。
  4. 心跳包:定时发送消息给服务器,防止连接因超时而断开。

通过结合这些方法,你可以有效地提高网络连接的稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值