简介:该7z压缩包收录了Delphi 13.1环境下的Devart SecureBridge v11.0.1 Professional组件库,面向使用Delphi与C++Builder进行网络应用开发的工程师。组件围绕SSH与SSL协议提供完整加密方案,涵盖数据加密传输、服务器身份验证、客户端授权等能力,可有效防止通信内容泄露与未授权访问,适合银行、医疗、政务等对安全等级要求较高的应用场景。包内共938个文件,包含153个pas单元源码、123个inc头文件以及86个dpk工程文件,这些核心代码为开发者提供了清晰的调用接口与定制空间;辅以res资源、dfm表单、bmp位图和Demos示例项目,能够直观展示组件在真实项目中的集成方式与配置流程。压缩包整体仅2.86MB,可快速下载并部署至本机开发环境,显著降低引入成本。同时附带帮助文档、图形化安装指南、许可协议与最新版下载指引,便于开发者完成环境配置并追踪版本更新信息。已有32人浏览学习,使用这些源码和示例,开发者能够在不依赖外部工具的前提下,自主实现安全通信模块,提升应用整体防护能力。适合希望为Delphi项目快速增加SSH/SSL安全层、并需要参考成熟实现与排错思路的中高级开发者。
1. 为什么还在用 Delphi 的项目,最后都绕不开 Devart SecureBridge
接手过一个老制造企业的 Delphi 库存系统,每天要把 ERP 导出的文件推到内网 Linux 服务器,还要远程重启服务。以前同事用 C/S 直接共享盘,后来安全策略收紧,要求所有维护操作必须走 SSH。翻了半天组件市场,最后还是留下了 Devart SecureBridge v11.0.1 Professional 这套控件。它让 Delphi 程序直接具备 SSH 客户端、SFTP 传输、SSL/TLS 通信能力,不需要额外拉 OpenSSL 命令行,也不需要你去理解底层 socket 状态机。对正在维护 Delphi 老项目、或者想在新项目里做安全文件交换的开发者来说,这是最省事的一条路,前提是你愿意踩过下面这些坑。
2. 把 SecureBridge v11.0.1 装进 Delphi 13.1:bpl 编译、IDE 注册与 License 路径
2.1 安装包结构:dpk、bpl、dcp 与 Sources 各自负责什么
解压后第一件事不是双击安装程序,而是先看清目录结构。这套 v11.0.1 Professional 包里通常是 Sources、Packages、Lib 三层。Sources 里是完整源码,遇到疑难杂症可以直接 F7 跟进;Packages 下按版本分了多个子目录,里面是 .dpk 工程文件;Lib 里放的是编译好的 .bpl 和 .dcp。
理解这三个目录很重要。.dpk 是 Delphi 包工程,打开它编译后生成 .bpl,这是真正会被 IDE 加载的运行时包;.dcp 是编译中间产物,IDE 在代码补全和链接时要用;Sources 则在你需要调试控件内部行为时才会真正派上用场。我第一次装的时候图省事直接去 Lib 找 bpl 加载,结果 IDE 报版本不匹配——后来才明白,官方预编译的 bpl 是为特定 RAD Studio 版本做的,与其碰运气,不如自己从 dpk 重新编一遍。
2.2 从命令行编译到 IDE 注册的完整步骤
在 Delphi 13.1 里编译第三方包,我习惯用命令行而不是 IDE 的 Build 菜单,因为能看到完整错误输出,出了问题能直接定位是哪个源文件缺依赖。先打开 RAD Studio 自带的命令提示符「RAD Studio Command Prompt」,它会把 dcc32、msbuild 的环境变量都配好。
cd /d D:\SecureBridge\Packages\Delphi13 msbuild SecureBridge.dproj /t:Build /p:Config=Release这里SecureBridge.dproj是包的主工程文件,/t:Build表示执行构建目标,/p:Config=Release指定用 Release 配置。编译完成后,同目录下会生成 SecureBridge.bpl 和 SecureBridge.dcp。如果这一步报错说找不到某个单元,八成是路径问题——检查Tools -> Options -> Delphi Options -> Library里的 Library Path 有没有把 Sources 目录加进去。
编译完成后,还需要让 IDE 认识这个包。打开Component -> Install Packages -> Add,选中刚生成的 SecureBridge.bpl,确定后工具面板里就会出现 TScSSHClient、TScSFTPClient 这一组控件,全部集中在「SecureBridge」面板下。这里有个反复出现的细节:如果 IDE 里之前装过旧版 SecureBridge,一定要先 Remove 旧包再 Add 新的,否则控件注册冲突会让你双击组件直接崩掉。
2.3 License 文件放哪、版本信息怎么看
Professional 版在编译安装本身不会卡你,但运行时行为受 License 文件控制。SecureBridge 的 License 文件名通常是securebridge.lic,我一般把它放在 exe 同目录,或者注册表指定的公共目录。组件在启动时会自动探测,找不到 License 时会走试用模式,功能不裁剪但会弹提示框,这在生产环境里不可接受。
判断 License 是否生效,看控件运行时的About属性,或者直接在TScSSHClient.Connect之前检查IsLicensed之类的运行时状态——具体属性名随版本略微不同,包里的帮助文档有列出。这条在部署到客户机时特别容易漏,打包安装程序时一定要把 License 文件作为单独一项加进去,我已经见过不止一个人把 exe 拷走了、License 忘了带。
3. TScSSHClient 实战:连接、认证与远程命令怎么在十分钟内跑通
3.1 拖一个 TScSSHClient:最小连接代码与参数清单
新建一个 Form,从 SecureBridge 面板拖一个TScSSHClient到窗体上,再拖一个TScSSHChannel。这两个是搭档关系:Client 负责 TCP 连接和 SSH 协议握手,Channel 负责在已建立的会话上开通道执行命令或转发数据。最小连接代码长这样:
procedure TForm1.ConnectBtnClick(Sender: TObject); begin ScSSHClient1.HostName := '192.168.10.20'; ScSSHClient1.Port := 22; ScSSHClient1.UserName := 'deploy'; ScSSHClient1.Password := 'P@ssw0rd'; ScSSHClient1.TimeOut := 30000; ScSSHClient1.Connect; LogMemo.Lines.Add('connected: ' + ScSSHClient1.ServerVersion); end;HostName和Port不用多说;UserName是登录账号;Password在快速验证时直接填,但生产环境不要写死在代码里,建议从配置文件加密读取;TimeOut单位是毫秒,这里设 30 秒,覆盖了 DNS 解析、TCP 握手和 SSH 版本协商的整个环节。连上之后读ServerVersion,拿到的就是远端 SSH 服务的版本字符串,比如 OpenSSH_8.2,能确认握手确实完成。
常见的错误是忘记设 TimeOut,默认值在某些版本里是 0,表示无限等待——网络不通时界面就像死了一样。所以我一律显式设置超时,这也方便后面做重连逻辑时判断错误类型。
3.2 认证方式:密码、私钥与键盘交互怎么选
密码认证最直接,但密钥认证才是生产环境的主流。TScSSHClient 支持私钥认证,关键是把密钥内容加载进TScSSHKeyStorage或者直接通过属性指定。操作面板上用PrivateKeyFile指定 PEM 私钥路径,同时把KeyStorage关联到一个TScSSHKeyStorage组件:
ScSSHKeyStorage1.LoadFromFile('id_rsa', ''); ScSSHClient1.KeyStorage := ScSSHKeyStorage1; ScSSHClient1.Authentication := [saPassword, saPublicKey]; ScSSHClient1.Connect;LoadFromFile的第一个参数是私钥路径,第二个参数是私钥密码——如果你的私钥文件本身有 passphrase,就填在这里,没有就传空串。Authentication属性是集合类型,saPublicKey表示允许公钥认证,saPassword作为兜底。我通常把两个都加上,这样服务器端禁用密码登录时,程序会自动走密钥;反过来密钥失效时还能靠密码登进去排查。这套设计比你自己判断服务器配置要可靠得多,因为不同的 SSH 服务器对认证方法协商顺序并不一样。
键盘交互认证(Keyboard Interactive)一般出现在需要动态令牌的场景,SecureBridge 也支持,通过OnKeyboardInteractive事件回调处理服务器发来的提示。这个事件里会收到服务器的问题文本,你把用户输入的答案写回Answers数组即可。国内不少堡垒机用的就是这种认证,值得提前测一下。
3.3 远程执行命令:把 stdout 和 exit code 拿回来
连接成功后,用 Channel 发命令。这里要给TScSSHChannel配上OnChannelData事件接收输出,另外一个TScSSHChannel默认是交互式 shell 模式,但执行一条独立命令应该用ExecCommand方式:
ScSSHChannel1.ChannelType := ctSession; ScSSHChannel1.ExecCommand('systemctl restart nginx');发出后,远程命令的 stdout 会分批到达OnChannelData事件,stderr 走OnChannelError。单纯这样只是把命令发出去,拿不到退出码和完整输出。要拿结果,得在OnChannelExitStatus事件里读取远端的 exit status,同时把 stdout 累积到一个字符串变量里,事件结束后统一处理:
procedure TForm1.ScSSHChannel1ChannelData(Sender: TObject; Channel: TScSSHChannel; Data: TBytes); var S: string; begin S := TEncoding.UTF8.GetString(Data); FOutputBuf := FOutputBuf + S; end; procedure TForm1.ScSSHChannel1ChannelExitStatus(Sender: TObject; Channel: TScSSHChannel; ExitStatus: Integer); begin LogMemo.Lines.Add('exit=' + ExitStatus.ToString); LogMemo.Lines.Add(FOutputBuf); FOutputBuf := ''; end;TBytes是未解码的原始字节,转字符串时用 UTF8 解码最稳妥——现在 Linux 服务器默认 locale 基本都是 UTF-8,你要是用 ANSI 去解,遇到中文说明文本直接乱码。ExitStatus对应远程命令的返回值,0 表示成功,非 0 就要把FOutputBuf里攒的出错信息作为排查依据。这套组合我称为「命令三件套」,凡是执行类操作都这么写,比把输出打印到 memo 里算完事强得多。
4. SFTP 传文件:TScSFTPClient 的上传下载、断点续传与进度回调
4.1 最小上传下载:StoreFile 与 RetrieveFile
SFTP 场景用TScSFTPClient,它内部自己管理 SSH 连接,不需要再额外挂 TScSSHClient。先连接,再调用StoreFile上传、RetrieveFile下载:
ScSFTPClient1.HostName := '192.168.10.20'; ScSFTPClient1.UserName := 'deploy'; ScSFTPClient1.Password := 'P@ssw0rd'; ScSFTPClient1.Connect; ScSFTPClient1.StoreFile('D:\data\stock_20250601.csv', '/home/deploy/import/stock_20250601.csv'); ScSFTPClient1.RetrieveFile('/home/deploy/export/result.txt', 'D:\data\result.txt'); ScSFTPClient1.Disconnect;StoreFile的第一个参数是本地文件,第二个是远端路径;RetrieveFile顺序相反。这套方法默认是整文件传输,小文件没问题,几十 MB 以上的文件建议先在本地做压缩再传。SecureBridge 的 StoreFile 底层是按块读写的,不需要你自己开文件流,对大多数场景封装得刚刚好。传完后最好调一次Disconnect,而不是把连接挂在那里等垃圾回收。
4.2 断点续传与进度回调的参数设置
断点续传是 SFTP 场景的刚需。SecureBridge 的TScSFTPClient支持续传,关键在TScSFTPFileTransfer类的StartPosition属性,或者使用支持续传的高层方法。如果你要自己做断点管理,在调用 StoreFile 前先查远端文件大小,把已传字节数作为起始偏移传进去:
var RemoteSize: Int64; LocalSize: Int64; begin RemoteSize := ScSFTPClient1.GetFileSize('/home/deploy/import/bigfile.zip'); LocalSize := TFile.GetSize('D:\data\bigfile.zip'); if RemoteSize < LocalSize then ScSFTPClient1.StoreFile('D:\data\bigfile.zip', '/home/deploy/import/bigfile.zip', RemoteSize) else LogMemo.Lines.Add('远端文件已完整,跳过'); end;StoreFile的第三个参数是起始偏移字节数,RemoteSize表示从远端已有大小处继续写。这样设计的好处是意外断线重连后,不用从头传几百 MB 的文件。注意GetFileSize在文件不存在时会返回 -1,要做防御判断。进度回调用OnProgress事件,参数里带 transmitted 和 size,你可以算百分比更新界面:
procedure TForm1.ScSFTPClient1Progress(Sender: TObject; Transmitted, Size: Int64); begin ProgressBar1.Max := Size; ProgressBar1.Position := Transmitted; end;Transmitted是已传输字节数,Size是本次操作总字节数。这个事件在高速传输时触发频率很高,不要在事件里写文件、写数据库这类耗时操作,否则会把传输速度拖下来。我一般只更新 ProgressBar 和当前字节数的 Label,其他都不要做。
4.3 目录遍历和文件操作:改名、删除与权限位
除了传文件,SFTP 客户端还承担远程文件管理的角色。SecureBridge 提供GetDir、DeleteFile、RenameFile、ChMod这些方法。日常运维里最常用的是目录遍历和权限修正:
var Items: TScDirList; Item: TScDirItem; begin Items := ScSFTPClient1.GetDir('/home/deploy/backup'); for Item in Items do begin if (Item.Attrs and faDirectory) = 0 then LogMemo.Lines.Add(Format('%s %d bytes', [Item.FileName, Item.Size])); end; end;GetDir返回TScDirList,每个TScDirItem包含文件名、大小、属性和修改时间。判断是不是目录,用TScSFTPClient里定义的faDirectory掩码去跟Item.Attrs做与运算,不要用 Windows 的faDirectory常量,那是 VCL 文件系统用的,两者数值相同但语义场景不同。需要改权限时用ChMod,传入八进制权限值,比如ChMod('/home/deploy/import/stock_20250601.csv', $0644),$0644就是 rw-r--r-- 的八进制写法。
5. SecureBridge 排雷实录:连接中断、中文乱码与线程崩溃的四个坑
5.1 连接成功,一执行命令就被远端断开
现象:TScSSHClient.Connect 成功,ServerVersion 也读到了,但 ExecCommand 后客户端立刻收到连接关闭,日志里只有一句 “Connection closed by remote host”。
原因:SSH 服务器开启了对 welcome banner 的强制处理,或者远端设置了MaxStartups、MaxSessions限制。最常见的是服务器会先发一个 banner 文本,客户端没读走这条数据,服务器认为客户端异常就掐了连接。
解决:给 TScSSHClient 挂OnServerBanner事件,先把 banner 读掉并记录到日志。另外检查服务器的/etc/ssh/sshd_config里MaxSessions是否太小,如果同一 IP 开了太多会话,需要调整这个值。
5.2 SFTP 上传中文文件名变乱码
现象:用 StoreFile 上传日报表.csv,到服务器上 ls 一看变成了æ¥æ¥è¡¨.csv这种乱码。
原因:SecureBridge 在 SFTP 协议层传输文件名时默认按 UTF-8 编码,而 Delphi 的 string 是 UTF-16。中文文件名在转换过程中,如果你的本地代码页不是 UTF-8,就会把字符串按 ANSI 转 UTF-8,得到错误的字节序列。
解决:在组装远端路径时显式做 UTF-8 转换,用UTF8Encode包一层。或者统一约定远端文件名只用 ASCII,这在大规模导入场景里最省心——维护一个文件名映射表,中文名留在本地,远端用日期加编号。
5.3 TimeOut 设了却不生效,连接卡了整整两分钟
现象:TimeOut 设了 20000,但连接失败时实际等了 120 秒才返回错误。
原因:TimeOut 属性控制的是 SSH 协议层的超时,而 TCP 层 connect 的超时在底层 socket 里走了系统默认值。特别是跨网段访问,SYN 包丢了之后系统要重试多次,这个时间不受控件 TimeOut 约束。
解决:把 TimeOut 设大其实没意义,真正要做的是在网络层做预检。我一般先 ping 一下目标地址,通了再走 SecureBridge;同时在调用 Connect 前用TScSSHClient.TcpClient的底层能力把连接超时也设一遍。SecureBridge 底层是异步模型,真正等不及可以直接调用CancelConnect方法取消当前连接流程。
5.4 UI 线程里传大文件,界面直接假死
现象:50 MB 文件传到一半,窗体拖不动,按钮点了没反应,传完才恢复。
原因:StoreFile 是同步阻塞方法,它在调用线程里完成整个传输过程。直接在按钮点击事件里调用,等于把 UI 线程占用了。
解决:放进 TThread 或 TTask 里执行,用TThread.CreateAnonymousThread包一层。SecureBridge 的控件可以在工作线程里创建和连接,不强制绑定主线程,这是它比某些老控件强的地方。做完之后用TThread.Queue把进度和完成消息回投到主线程更新界面。这里注意一个细节:跨线程共享同一个 TScSFTPClient 实例不行,每个线程各自 new 一个出来用,用完释放,不要图省事共用。
6. 手写一个小工具:用 TScSSHLog 把握手过程变成可读日志
排查 SecureBridge 问题最有效的手段是从协议层看日志,而不是猜。SecureBridge 自带TScSSHLog组件,把它和 TScSSHClient 关联起来,能记录从 TCP 连接到 SSH 版本协商、密钥交换、认证方法的完整细节。这个习惯帮我解决过很多「玄学」问题——比如某台服务器连续三台客户端都能连,就我们的程序连不上,打开日志一看,是对方只支持ssh-rsa而客户端密钥交换列表里没带这个算法。
最小用法是做一个独立日志窗体,把 TScSSHLog 的FileName指向一个文本文件,Active设为 True,它就会把协议数据写进去。关键参数有两个:LogPackets控制是否记录原始数据包,打开后日志非常详细但也非常占空间,排查握手问题时才开;LogKeys控制是否记录密钥交换产生的密钥信息,生产环境不要开,有安全风险。我一般把日志级别留在默认,先拿到事件序列,按时间戳看卡在哪个阶段:
ScSSHLog1.FileName := 'D:\logs\ssh_debug_' + FormatDateTime('yyyymmdd_hhnnss', Now) + '.log'; ScSSHLog1.Active := True; ScSSHLog1.Client := ScSSHClient1;FileName带时间戳是为了每次排查都留独立的文件,不至于多次调试互相覆盖。Client属性是关联点,关联后 TScSSHClient 每走一个协议状态,日志里都会有一行。看到SSH_MSG_KEXINIT之后没有后续,说明密钥交换算法协商失败;看到认证方法列表里只有none,说明服务器配置了禁止密码登录而你的客户端没带密钥。这些都是猜不出来的,日志会直接告诉你。
从那以后,我每次给客户部署 SecureBridge 相关程序,都强制在安装包里保留日志开关,默认关、出问题时开。遇到一次连不上的问题,先开日志再复现,基本十分钟内能定位到是网络、密钥还是服务器配置的问题。这套流程也让售后沟通成本低了很多——直接让客户把日志文件发过来就行。希望帮到你。
本文还有配套的精品资源,点击获取