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

Delphi中TIdCmdTcpServer连接后启用Start TLS的服务器端配置问题

解决Indy SSL动态加密连接问题(基于证书存在性)

服务器端修改步骤

1. 预先检测SSL证书有效性

在服务器启动时,检查证书文件是否存在且可正常加载,标记当前服务器是否支持SSL加密:

private
  FHasValidSSL: Boolean;
...

procedure TIndyTcpCommandReceiver.FormCreate(Sender: TObject);
begin
  FHasValidSSL := False;
  // 替换为你的证书路径配置
  if FileExists(IdServerIOHandlerSSLOpenSSL1.SSLOptions.CertFile) and 
     FileExists(IdServerIOHandlerSSLOpenSSL1.SSLOptions.KeyFile) then
  begin
    try
      // 尝试加载证书验证有效性
      IdServerIOHandlerSSLOpenSSL1.SSLOptions.CertFile := IdServerIOHandlerSSLOpenSSL1.SSLOptions.CertFile;
      IdServerIOHandlerSSLOpenSSL1.SSLOptions.KeyFile := IdServerIOHandlerSSLOpenSSL1.SSLOptions.KeyFile;
      FHasValidSSL := True;
    except
      FHasValidSSL := False;
    end;
  end;
end;

2. 移除原连接事件中的强制SSL代码

彻底删除TCPServerConnect事件里设置PassThrough := false的代码,让初始连接保持明文状态:

// 原代码全部移除,不要保留
// procedure TIndyTcpCommandReceiver.TCPServerConnect(AContext: TIdContext);
// begin
//   if AContext.Connection.IOHandler is TIdSSLIOHandlerSocketOpenSSL then
//     TIdSSLIOHandlerSocketOpenSSL(AContext.Connection.IOHandler).PassThrough := false;
// end;

3. 添加SSL协商命令(推荐方案)

利用TIdCmdTCPServer的命令机制,新增START_SSL命令让客户端主动询问并触发加密切换:

  1. 在TIdCmdTCPServer的Commands集合中添加一个命令,Command属性设为START_SSL,ReplyNormal设为200 SSL enabled。
  2. 实现命令处理函数:
procedure TIndyTcpCommandReceiver.IdCmdTCPServer1START_SSLCommand(ASender: TIdCommand);
var
  SSLIOHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
  if not FHasValidSSL then
  begin
    ASender.Reply.SetReply(500, 'SSL not available on this server');
    Exit;
  end;

  if ASender.Context.Connection.IOHandler is TIdSSLIOHandlerSocketOpenSSL then
  begin
    SSLIOHandler := TIdSSLIOHandlerSocketOpenSSL(ASender.Context.Connection.IOHandler);
    SSLIOHandler.PassThrough := False;
    ASender.Reply.SetReply(200, 'SSL enabled');
  end
  else
  begin
    ASender.Reply.SetReply(500, 'SSL not supported by server');
  end;
end;

客户端对应调整

修改客户端连接逻辑,先建立明文连接,再发送命令协商SSL:

procedure TTCPConnector.Connect;
var
  Response: string;
begin
  FSSLIOHandler.PassThrough := true;
  FTCPClient.Connect(FServerName, FPort);

  // 发送SSL协商命令
  FTCPClient.IOHandler.WriteLn('START_SSL');
  Response := FTCPClient.IOHandler.ReadLn;

  // 根据服务器响应决定是否切换加密模式
  if StartsStr('200', Response) then
  begin
    FSSLIOHandler.PassThrough := false;
    // 后续通信已加密
  end
  else
  begin
    // 保持明文通信
  end;
end;

替代方案(无需命令协商)

如果不想修改客户端命令逻辑,可在服务器OnExecute事件中检测SSL握手请求并动态切换:

procedure TIndyTcpCommandReceiver.IdCmdTCPServer1Execute(AContext: TIdContext);
var
  SSLIOHandler: TIdSSLIOHandlerSocketOpenSSL;
  Buffer: TIdBytes;
  BytesRead: Integer;
begin
  if not FHasValidSSL then Exit;

  SSLIOHandler := TIdSSLIOHandlerSocketOpenSSL(AContext.Connection.IOHandler);
  if SSLIOHandler.PassThrough then
  begin
    // 检测SSL Client Hello的起始字节(0x16)
    BytesRead := SSLIOHandler.CheckForDataOnSource(100);
    if BytesRead > 0 then
    begin
      SSLIOHandler.ReadBytes(Buffer, 1, False);
      if Buffer[0] = $16 then
      begin
        SSLIOHandler.PassThrough := False;
        // 将读取的字节放回输入缓冲区,让SSL握手正常处理
        SSLIOHandler.InputBuffer.Add(Buffer);
      end;
    end;
  end;
end;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:24:53