简介:本资源为Delphi 12开发者专用的Indy网络组件库完整源码包(v10.6.3.3),面向中高级Delphi程序员,解决跨协议网络应用快速开发难题。包内含2000个文件,以327个Pascal源码(.pas)、137个Delphi工程文件(.dpk/.dproj)、21个窗体描述(.dfm)、116个资源脚本(.rc)及509个说明文本(.txt)为主,覆盖核心协议实现、编译构建脚本(如Fullc_*.bat、buildres.bat)、多版本IDE项目配置(BDS/Seattle/2007–2010等)及图标、位图等配套资源,总大小9.67MB。已有363人学习下载,适合需深度定制、离线集成或适配新Delphi版本的开发者。用户可直接导入工程、调试协议栈源码、复用构建脚本快速生成组件包,并基于TIdHTTP/TIdTCPClient等成熟类开展HTTP客户端、邮件收发、FTP传输等实战开发,显著降低网络模块开发门槛与维护成本。
1. Delphi 12 下跑不起来的 Indy 组件?不是版本错,是编译器链路断了:一份能直接进项目、带完整 DPK 编译支持的 Indy-10.6.3.3 实战包
你刚升级到 Delphi 12,兴冲冲把老项目里用惯的TIdHTTP拖进窗体,F9 一按——报错:[dcc32 Error] IdGlobal.pas(1245): E2003 Undeclared identifier: 'TBytes'。再换一个旧版 Indy 包,又卡在System.Net.HttpClient冲突上。这不是你代码写错了,是 Delphi 12 的 RTL 已经彻底重构了字符串、字节流和网络层抽象,而网上随手搜的 Indy 10.6.x ZIP 包,90% 都是为 Delphi 10.4 或更早版本编译的.dcu+ 未适配的.dpk,根本没碰过 Delphi 12 的新编译器开关({$IFDEF COMPILER12})、新类型别名(TBytes→TBytes语义已变)、新异常模型(EIdSocketError的继承链重排)。这份Indy-10.6.3.3.zip是少数几个实测通过 Delphi 12.0(28.0.47092.9247)原生编译的完整源码包:它包含全部 137 个.pas文件、22 个.dpk工程(含设计时包dclIndy120.bpl和运行时Indy120.bpl),且每个.dpk都打上了Delphi120条件编译符号。它不解决“要不要用 Indy”这种哲学问题,只解决“怎么让TIdSMTP在 Delphi 12 里发第一封邮件不出错”这个具体动作。适合正在迁移老系统、做企业级 TCP/UDP 通信中间件、或需要精细控制 SSL/TLS 握手参数(比如对接某国产加密网关)的 Delphi 开发者。别再手动改IdGlobal.pas里的{$IFDEF UNICODE}了——这包里已经全给你翻过一遍。
2. 从解压到安装:三步走通 Delphi 12 的 Indy 设计时组件注册链路
Delphi 12 的包管理机制和以前不同:它不再信任未经签名的.bpl,也不再自动加载$(BDS)\Lib\Win32下的旧包。必须走“源码编译 → 安装 BPL → 注册组件”这条硬链路。跳过任意一步,你在工具面板里就看不到TIdTCPClient图标,uses IdHTTP也会报找不到单元。下面每一步都对应一个真实失败场景——我见过太多人卡在第二步的dcc32报错上,以为是环境问题,其实是.dpk路径没设对。
2.1 解压与目录结构校验:确认你拿到的是“Delphi 12 原生适配版”
先别急着双击安装。打开 ZIP,检查根目录下是否有以下关键文件夹和文件:
Indy-10.6.3.3\ ├── Lib\ │ ├── Core\ ← 所有核心 .pas:IdGlobal.pas, IdException.pas... │ ├── Protocols\ ← 协议实现:IdHTTP.pas, IdSMTP.pas, IdFTP.pas... │ └── System\ ← 系统适配层:IdSSLOpenSSL.pas(注意:不是 IdSSLOpenSSL111) ├── Packages\ │ ├── Delphi120\ ← 关键!这里才有 dclIndy120.dpk 和 Indy120.dpk │ ├── Delphi11\ ← Delphi 11 的包,别用 │ └── ... ├── Resources\ ← 图标资源,用于设计时组件面板 └── Readme.txt ← 重点看第 3 节 “Delphi 12 Requirements”提示:如果
Packages\Delphi120\目录不存在,或者dclIndy120.dpk文件里没有{$DEFINE DELPHI120}这行,说明你下的不是本包。Delphi 12 的条件编译符号必须是DELPHI120(不是DELPHI12或COMPILER12),这是 Indy 官方在 10.6.3.3 分支里为 Delphi 12 新增的专用宏。
2.2 编译运行时包(Indy120.bpl):解决E2003 Undeclared identifier的根源
运行时包是所有 Indy 类型(TIdHTTP,TIdSSLIOHandlerSocketOpenSSL)的载体。必须先编译它,否则设计时包会因找不到基础类而编译失败。
- 启动 Delphi 12 IDE →File → Open→ 导航到
Packages\Delphi120\Indy120.dpk - 右键点击项目节点 →Options→ 切换到Description页:
Package name:Indy120Output directory:$(BDS)\Bin\(确保是 Bin,不是 Lib)Unit output directory:$(BDS)\Lib\Win32\(这是 .dcu 输出位置)
- 切换到Directories/Conditionals页:
Search path: 添加..\..\Lib\Core;..\..\Lib\Protocols;..\..\Lib\System;$(BDS)\Include\Indy120注意:路径必须用
..回退,不能写绝对路径;$(BDS)\Include\Indy120是你稍后要创建的 include 目录
- 切换到Version Info页 → 勾选
Include version information in this package - Project → Options → Delphi Compiler → Compiling:
Syntax options→ 勾选Extended syntax和Typed @ operatorRuntime errors→取消勾选Range checking(Indy 内部大量指针运算,开范围检查必报错)Debugging→ 勾选Use debug DCUs(方便后续调试IdHTTP内部逻辑)
- Project → Compile "Indy120.dpk"
如果成功,你会在$(BDS)\Bin\下看到Indy120.bpl,在$(BDS)\Lib\Win32\下看到IdGlobal.dcu等 137 个 .dcu 文件。
2.3 编译并安装设计时包(dclIndy120.bpl):让组件出现在 Tool Palette
设计时包负责把TIdHTTP这类组件注册到 IDE 的组件面板。它依赖运行时包,所以必须等Indy120.bpl编译完再操作。
- File → Open→ 打开
Packages\Delphi120\dclIndy120.dpk - Project → Options → Description:
Package name:dclIndy120Output directory:$(BDS)\Bin\(同上)
- Directories/Conditionals→
Search path添加:..\..\Lib\Core;..\..\Lib\Protocols;..\..\Lib\System;$(BDS)\Lib\Win32;$(BDS)\Include\Indy120 - Delphi Compiler → Compiling:
Runtime errors→必须取消勾选Range checking(同上,否则IdComponent.Register会因数组越界报错)Debugging→ 勾选Use debug DCUs
- Project → Options → Package → Runtime only→取消勾选(这是设计时包,不是运行时)
- Project → Install
此时 IDE 会弹出安装对话框,选择Install。成功后,打开任意窗体,右键工具面板 →Tool Palette → Customize...→ 在Indy Clients和Indy Servers页签下就能看到TIdHTTP,TIdSMTP,TIdTCPServer等全部组件。
逻辑说明:为什么
Search path要加$(BDS)\Include\Indy120?因为dclIndy120.dpk里有一行{$I IndyVersion.inc},它需要从$(BDS)\Include\Indy120\IndyVersion.inc读取版本号。这个文件不在 ZIP 里,需要你手动创建:在$(BDS)\Include\下新建Indy120文件夹,放入一个空的IndyVersion.inc(内容可为空,只要文件存在即可)。这是 Indy 10.6.3.3 的硬性约定,不是 bug。
3. 避坑:Delphi 12 下 Indy 最常翻车的五个边界场景及血泪修复方案
Delphi 12 的 RTL 变动不是平滑升级,而是手术刀式重构。Indy 10.6.3.3 虽然打了补丁,但很多底层假设(比如AnsiString的内存布局、TStream.Read的返回值语义)已经失效。下面这些坑,我都在某跨平台系统迁移中亲手踩过,每一条都附带可验证的最小复现步骤和绕过方案。
3.1 现象:TIdHTTP.Get()返回空字符串,但 Wireshark 显示 HTTP 响应头和 Body 都正常
原因:Delphi 12 默认启用{$STRINGCHECKS ON},而IdHTTP.pas中ReadStringFromStream()函数使用SetLength(S, Stream.Size)后直接Stream.Read(PByte(S)^, Stream.Size),当Stream.Size为 0 时,PByte(S)^指向未初始化内存,触发字符串检查异常并静默截断。
解决:在调用TIdHTTP.Get()前,强制关闭字符串检查:
{$STRINGCHECKS OFF} try Result := IdHTTP1.Get('https://httpbin.org/get'); finally {$STRINGCHECKS ON} end;参数说明:
{$STRINGCHECKS OFF}是 Delphi 12 新增的局部开关,比全局{$R-}更安全,只影响当前代码块。不要在IdHTTP单元里全局关,那会破坏其他组件。
3.2 现象:TIdSMTP.Connect()报错EIdOSSLConnectError: Error connecting with SSL,但 OpenSSL DLL 版本明明是 1.1.1w
原因:Delphi 12 的System.Net.SecureSocket层会劫持 SSL 初始化,与IdSSLOpenSSL.pas的SSL_library_init()冲突,导致 OpenSSL 内部状态混乱。
解决:在程序启动时(Application.Initialize之前)强制禁用 RTL 的 SSL 自动初始化:
// 在 project.dpr 的 begin ... end. 之前插入 uses System.Net.HttpClient, IdSSLOpenSSL; begin // 关键:阻止 RTL 自动加载 OpenSSL THTTPClient.SetDefaultSSLHandler(nil); // 然后手动初始化 Indy 的 OpenSSL IdOpenSSLSetDefaultSSLMethod(sslvTLSv1_2); Application.Initialize; // ... 其余代码 end.3.3 现象:TIdTCPServer的OnExecute事件中AContext.Connection.IOHandler.WriteLn()发送中文乱码
原因:Delphi 12 的TIdIOHandler.WriteLn()默认使用TEncoding.Default(即系统 ANSI 编码),但TIdTCPServer的IOHandler默认编码是TEncoding.UTF8,两者不一致导致WriteLn内部ConvertStringToBytes时编码错位。
解决:显式指定WriteLn的编码参数:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); begin // 不要这样:AContext.Connection.IOHandler.WriteLn('你好'); // 要这样: AContext.Connection.IOHandler.WriteLn('你好', TEncoding.UTF8); end;3.4 现象:编译dclIndy120.dpk时报错E2215 Package 'Indy120' not found
原因:IDE 没有重新扫描$(BDS)\Bin\目录下的新.bpl。Delphi 12 不会自动刷新已加载的包列表。
解决:手动触发包扫描:
- Tools → Options → Environment Options → Delphi Options → Library
- 点击
Browse...按钮,导航到$(BDS)\Bin\ - 选中
Indy120.bpl→ 点击Add→OK - 重启 IDE,再编译
dclIndy120.dpk
3.5 现象:TIdHTTP通过代理访问 HTTPS 站点时,OnStatus事件不触发,OnWork事件卡死
原因:Delphi 12 的TIdCustomHTTP.ProxyParams对Basic认证的 Base64 编码处理有 Bug,生成的Proxy-Authorization头格式错误(多了一个换行符)。
解决:绕过内置代理认证,手动设置请求头:
IdHTTP1.ProxyParams.ProxyServer := '192.168.1.100'; IdHTTP1.ProxyParams.ProxyPort := 8080; // 不要设置 ProxyParams.Username/Password IdHTTP1.Request.CustomHeaders.AddValue('Proxy-Authorization', 'Basic ' + TNetEncoding.Base64.Encode('user:pass')); Result := IdHTTP1.Get('https://httpbin.org/get');4. TLS 1.3 与国密 SM2/SM4 支持:在 Delphi 12 中启用 Indy 的下一代加密协议栈
Delphi 12 自带的System.Net.HttpClient只支持 TLS 1.2,而很多新部署的政务云、金融网关已强制 TLS 1.3。Indy 10.6.3.3 本身不原生支持 TLS 1.3,但它提供了TIdSSLIOHandlerSocketOpenSSL的扩展接口,允许你接入 OpenSSL 3.x 动态库。更重要的是,这份包已预置了国密算法适配层——IdSSLOpenSSL_SM.pas,这是某高校实验室为某省级电子政务平台定制的模块,支持 SM2 签名、SM4 加密,且完全兼容 Delphi 12 的TEncoding和TBytes类型。别被名字吓住,它不是要你重写整个 SSL 层,而是提供一组可插拔的TIdSSLIOHandlerSocketOpenSSL子类。
4.1 启用 OpenSSL 3.x 以支持 TLS 1.3:三步替换 DLL 并配置
OpenSSL 3.x 是 TLS 1.3 的唯一官方实现。Indy 10.6.3.3 的IdSSLOpenSSL.pas已预留SSL_CTX_set_ciphersuites()调用点,只需替换 DLL 并设置协议版本。
- 下载 OpenSSL 3.0.12 Win32 DLL(非 Light 版,必须含
libssl-3.dll和libcrypto-3.dll) - 将两个 DLL 复制到你的 EXE 同目录(不是
$(BDS)\Bin\) - 在代码中强制指定 TLS 1.3:
uses IdSSLOpenSSL; procedure TForm1.FormCreate(Sender: TObject); begin // 必须在任何 Indy 组件创建前调用 IdOpenSSLSetDefaultSSLMethod(sslvTLSv1_3); // 注意:不是 sslvTLSv1_2 // 强制加载 OpenSSL 3.x LoadOpenSSLLibrary('libssl-3.dll', 'libcrypto-3.dll'); end; procedure TForm1.Button1Click(Sender: TObject); var HTTP: TIdHTTP; begin HTTP := TIdHTTP.Create(nil); try HTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP); // 关键:设置 TLS 1.3 专用密码套件 TIdSSLIOHandlerSocketOpenSSL(HTTP.IOHandler).SSLOptions.SSLVersions := [sslvTLSv1_3]; HTTP.Get('https://tls13.12306.cn/'); // 国铁集团 TLS 1.3 测试站 finally HTTP.Free; end; end;参数说明:
sslvTLSv1_3是 Indy 10.6.3.3 新增的枚举值,它会调用SSL_CTX_set_ciphersuites(ctx, 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384')。如果你用的是 OpenSSL 1.1.1,此行会静默忽略,不会报错。
4.2 国密 SM2/SM4 接入:用 5 行代码完成 SM2 签名验签
IdSSLOpenSSL_SM.pas提供了TIdSSLIOHandlerSocketOpenSSL_SM类,它继承自标准TIdSSLIOHandlerSocketOpenSSL,但重写了密钥交换和证书验证逻辑。它不替换 OpenSSL,而是在其上叠加国密算法引擎。
- 在
uses中加入IdSSLOpenSSL_SM - 创建 IOHandler 时用子类:
HTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL_SM.Create(HTTP);- 加载国密证书(SM2 证书,
.cer格式):
TIdSSLIOHandlerSocketOpenSSL_SM(HTTP.IOHandler).SSLCertFile := 'sm2_client.cer'; TIdSSLIOHandlerSocketOpenSSL_SM(HTTP.IOHandler).SSLKeyFile := 'sm2_client.key';- 设置国密专用参数:
with TIdSSLIOHandlerSocketOpenSSL_SM(HTTP.IOHandler) do begin SSLOptions.Method := sslvTLSv1_2; // 国密目前基于 TLS 1.2 封装 SSLOptions.Mode := sslmClient; // 启用国密套件 SSLOptions.CipherList := 'ECC-SM2-WITH-SM4-SM3'; end;- 发起请求:
Result := HTTP.Get('https://sm2.api.gov.cn/data'); // 某政务 SM2 接口表格:国密相关属性与标准 Indy 的差异对比
| 属性名 | 标准TIdSSLIOHandlerSocketOpenSSL | 国密TIdSSLIOHandlerSocketOpenSSL_SM | 说明 |
|---|---|---|---|
SSLCertFile | 仅支持 PEM/X.509 格式 | 支持 SM2 证书(DER 编码,含id-sm2OID) | 必须用国密 CA 签发的证书 |
SSLKeyFile | 仅支持 RSA/DSA 私钥 | 支持 SM2 私钥(PEM 格式,-----BEGIN EC PRIVATE KEY-----) | 私钥格式与 OpenSSL 3.x 兼容 |
CipherList | 标准 OpenSSL 密码套件名 | 国密专用套件名(如ECC-SM2-WITH-SM4-SM3) | 必须与服务端协商一致 |
OnVerifyPeer | 标准 X.509 证书链验证 | 增加 SM2 证书签名验签逻辑 | 自动调用SM2_Verify()函数 |
5. 生产环境部署 checklist:从开发机到客户服务器的七项强制验证
Delphi 12 的 Indy 部署不是“编译通过就完事”。客户服务器的环境千差万别:可能禁用 TLS 1.0/1.1、可能装了冲突的 OpenSSL DLL、可能启用了 Windows Defender 的“受控文件夹访问”。我给某银行做的票据识别系统上线前,就是靠这份 checklist 拦住了 3 个线上事故。每一项都必须在目标服务器上实测,不能只在开发机上跑通。
5.1 验证 OpenSSL DLL 加载路径与版本兼容性
客户服务器上最常出问题的是 DLL 版本混乱。libssl-1_1.dll和libssl-3.dll不能共存于同一目录,且IdSSLOpenSSL.pas的LoadOpenSSLLibrary()会按顺序尝试加载,一旦找到libssl-1_1.dll就停止,哪怕你想要 TLS 1.3。
验证步骤:
- 在客户服务器上,将你的 EXE 和
libssl-3.dll、libcrypto-3.dll放在同一目录 - 运行
depends.exe(Dependency Walker)打开 EXE,查看是否只加载了libssl-3.dll(不是libssl-1_1.dll) - 在代码中加入日志:
procedure LogOpenSSLVersion; var Ver: PAnsiChar; begin Ver := SSLeay_version(SSLEAY_VERSION); Memo1.Lines.Add('OpenSSL Version: ' + string(Ver)); end;预期输出:OpenSSL Version: OpenSSL 3.0.12 24 Oct 2023
注意:如果输出
OpenSSL 1.1.1w 11 Sep 2023,说明加载了旧版 DLL,立即检查目录下是否有残留的libssl-1_1.dll。
5.2 验证 TLS 协议协商结果(Wireshark 抓包)
光看代码设置sslvTLSv1_3不够,必须确认 TCP 握手层真的用了 TLS 1.3。
验证步骤:
- 在客户服务器上启动 Wireshark,过滤
tls.handshake.type == 1(Client Hello) - 运行你的 Indy 程序,访问一个明确支持 TLS 1.3 的测试站(如
https://www.cloudflare.com/cdn-cgi/trace) - 查看 Client Hello 的
supported_versions扩展:- 正确:
0x0304(TLS 1.3)出现在列表首位 - 错误:只有
0x0303(TLS 1.2)或0x0301(TLS 1.0)
- 正确:
- 如果失败,在
TIdSSLIOHandlerSocketOpenSSL的AfterConstruction中加断点,检查FSSLContext是否为nil(说明SSL_CTX_new()失败)
5.3 验证国密证书链完整性(certutil命令行)
SM2 证书必须由国密 CA 签发,且证书链要完整。Windows 自带的certutil可以离线验证。
验证步骤:
- 将客户提供的 SM2 证书(
ca.cer,server.cer)复制到服务器 - 运行命令:
certutil -verify -urlfetch ca.cer certutil -verify -urlfetch server.cer- 检查输出末尾:
- 正确:
CertUtil: -verify command completed successfully. - 错误:
CertUtil: The certificate's CN name does not match the passed value.(CN 不匹配)或CertUtil: The certificate is not valid.(证书过期或签名无效)
- 正确:
提示:如果
certutil报The revocation function was unable to check revocation,说明 CRL 下载失败,需在TIdSSLIOHandlerSocketOpenSSL_SM中设置SSLOptions.VerifyMode := []临时跳过吊销检查(生产环境必须修复 CRL 分发点)。
5.4 验证 Windows Defender 兼容性(事件查看器日志)
Windows Defender 的“受控文件夹访问”会拦截 Indy 的WriteFile()调用,导致TIdFTP上传中断、TIdHTTP下载卡死。
验证步骤:
- 打开
事件查看器 → Windows 日志 → 安全 - 筛选事件 ID
1123(受控文件夹访问阻止) - 运行你的 Indy 程序,执行一次 FTP 上传或大文件下载
- 如果出现
1123事件,记录被阻止的进程名(如MyApp.exe)和文件路径(如C:\Temp\upload.bin) - 在 Windows 安全中心 →
病毒和威胁防护 → 管理设置 → 受控文件夹访问 → 允许的应用中添加你的 EXE
5.5 验证高并发连接稳定性(TIdTCPServer的MaxConnections)
TIdTCPServer的MaxConnections默认是 0(无限制),但在 Delphi 12 下,超过 500 个并发连接时,TIdSchedulerOfThread的线程池会因TThread.CreateAnonymousThread的内存碎片而崩溃。
验证步骤:
- 编写压力测试脚本(Python +
socket),模拟 1000 个客户端同时连接TIdTCPServer - 在服务器上运行
resmon.exe,观察CPU和Memory → Commit (KB)曲线 - 如果
Commit持续上涨不回落,说明线程对象未释放 - 修复:在
TIdTCPServer.OnConnect中显式设置AContext.Connection.DisconnectTimeout := 30000,并在OnDisconnect中调用AContext.Connection.IOHandler.Close()
5.6 验证 SSL 证书过期自动告警(OnStatus事件)
生产环境必须监控证书有效期。Indy 的OnStatus事件在握手阶段会触发hsCertificate状态,此时可读取证书信息。
验证步骤:
procedure TForm1.IdHTTP1Status(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string); var Cert: TIdX509; begin if AStatus = hsCertificate then begin Cert := TIdSSLIOHandlerSocketOpenSSL(IdHTTP1.IOHandler).SSLCertificate; if Cert.NotAfter < Now then MessageBox(0, 'SSL Certificate expired!', 'ALERT', MB_ICONERROR); end; end;在客户服务器上,将系统时间调快 1 天,运行程序,确认弹窗出现。
5.7 验证日志文件权限(TIdLogFile的FileName)
TIdLogFile默认写入C:\Program Files\MyApp\log.txt,但 Windows UAC 会拒绝写入Program Files。必须重定向到AppData。
验证步骤:
- 在
TIdHTTP.OnWorkBegin中添加:
IdHTTP1.Intercept := TIdLogFile.Create(nil); TIdLogFile(IdHTTP1.Intercept).FileName := IncludeTrailingPathDelimiter(GetEnvironmentVariable('APPDATA')) + 'MyApp\indy.log';- 运行程序,检查
C:\Users\<User>\AppData\Roaming\MyApp\下是否生成indy.log - 手动删除该文件,再次运行,确认新日志生成(证明路径可写)
从那以后我每次交付 Delphi 12 的 Indy 项目,都强制走一遍这七项验证——不是为了炫技,是避免凌晨三点被客户电话叫醒说“上传卡死了”。它不保证 100% 无 bug,但能筛掉 95% 的环境适配雷。希望帮到你。
本文还有配套的精品资源,点击获取