Delphi网络编程综合实战:多协议网络工具开发(TCP/UDP/HTTP三合一)

张开发
2026/4/20 21:47:23 15 分钟阅读

分享文章

Delphi网络编程综合实战:多协议网络工具开发(TCP/UDP/HTTP三合一)
Delphi网络编程综合实战多协议网络工具开发TCP/UDP/HTTP三合一前四篇我们分别讲解了Delphi网络编程的核心组件TCP、UDP、HTTP、进阶技能自定义协议、数据加密、断点续传掌握了单个模块的用法但实际项目中往往需要整合多种网络协议实现多场景适配。本文将以「多协议网络工具」为实战案例整合TCP客户端/服务端、UDP客户端/服务端、HTTP请求/断点下载三大核心功能复用前序文章的工具类协议、加密完整实现从界面设计、代码编写、功能测试到异常处理的全流程帮助你打通知识点提升综合开发能力最终实现一个可直接使用的桌面端网络工具。工具核心功能支持TCP双向通信、UDP单播/广播、HTTP GET/POST请求、HTTP断点续传内置数据加密、日志记录、异常处理适配日常开发调试、设备通信测试等场景。一、项目需求与整体设计1. 核心需求TCP模块支持TCP客户端连接、发送/接收数据、TCP服务端监听、多客户端连接、数据转发UDP模块支持UDP客户端单播/广播发送、接收数据、UDP服务端监听、回复数据HTTP模块支持GET/POST请求普通请求、JSON提交、HTTP断点续传下载文件、暂停/继续通用功能数据加密AES、自定义协议、日志记录、异常提示、界面无卡死多线程易用性分标签页展示不同功能操作简洁支持参数配置IP、端口、密钥等。2. 整体架构设计采用「分层设计模块化封装」降低耦合度方便后续扩展架构分为3层UI层主窗体标签页、各功能模块界面TCP、UDP、HTTP、控件交互业务逻辑层各协议的核心逻辑TCP通信、UDP通信、HTTP请求/下载、线程管理工具层复用前序文章的协议工具类Unit_Protocol.pas、加密工具类Unit_Encryption.pas新增日志工具类。3. 环境准备Delphi版本Delphi XE及以上本文以Delphi 10.4为例依赖组件Indy组件库自带无需额外安装、System.JSONJSON解析、System.Security.CryptographyAES加密工具类依赖Unit_Protocol.pas自定义协议、Unit_Encryption.pas数据加密需提前准备参考上一篇文章。二、界面设计核心部分主窗体采用标签页TTabControl分为4个标签页TCP模块、UDP模块、HTTP请求、HTTP下载每个标签页对应一个功能模块界面简洁易用控件命名规范便于代码编写。1. 主窗体整体布局1个TTabControltabMain4个标签页tabTCP、tabUDP、tabHTTPReq、tabHTTPDownload1个TMemomemoLog全局日志显示记录所有操作、通信数据、异常信息1个TButtonbtnClearLog清空日志公共配置区AES密钥输入框edtAESKey、协议开关chkUseProtocol控制是否启用自定义协议和加密。2. TCP模块界面tabTCP客户端区域IP输入框、端口输入框、连接/断开按钮、发送内容输入框、发送按钮服务端区域监听端口输入框、启动/停止服务按钮数据显示区域接收数据显示框TMemo。3. UDP模块界面tabUDP客户端区域目标IP、目标端口、发送内容、单播发送/广播发送按钮服务端区域监听端口、启动/停止监听按钮数据显示区域接收数据显示框TMemo。4. HTTP请求界面tabHTTPReq请求配置请求地址URL、请求方式GET/POSTTRadioGroup请求参数GET参数输入框、POST参数普通表单/JSON切换按钮操作按钮发送请求、清空响应响应显示响应内容、响应码、响应时间TMemoTLabel。5. HTTP下载界面tabHTTPDownload下载配置下载地址URL、保存路径输入框浏览按钮操作按钮开始下载、暂停/继续下载、停止下载进度显示进度条TProgressBar、进度信息下载速度、已下载/总大小。三、核心代码实现分模块代码采用模块化编写每个功能模块单独封装方法复用前序工具类重点实现多线程、多协议整合、异常处理确保工具稳定运行。1. 日志工具类新增Unit_Log.pas封装全局日志记录方法支持线程安全统一日志格式便于调试和问题排查。unit Unit_Log; interface uses System.SysUtils, System.Classes, Vcl.StdCtrls; type TLogTool class public // 记录日志线程安全支持传入Memo控件显示 class procedure Log(Msg: string; Memo: TMemo); // 清空日志 class procedure ClearLog(Memo: TMemo); end; implementation { TLogTool } class procedure TLogTool.ClearLog(Memo: TMemo); begin TThread.Synchronize(nil, procedure begin Memo.Clear; end); end; class procedure TLogTool.Log(Msg: string; Memo: TMemo); var LogStr: string; begin LogStr : FormatDateTime(yyyy-mm-dd hh:MM:ss.zzz, Now) | Msg; TThread.Synchronize(nil, procedure begin Memo.Lines.Add(LogStr); // 自动滚动到最后一行 Memo.SelStart : Length(Memo.Text); Memo.Perform(EM_SCROLLCARET, 0, 0); end); end; end.2. 主窗体核心代码MainForm.pas主窗体整合所有功能sccla.cn/pacy7模块实现控件交互、线程管理、功能调用核心代码如下重点展示多协议整合逻辑完整代码可参考注释补充。unit MainForm; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Buttons, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdTCPServer, IdUDPBase, IdUDPClient, IdUDPServer, IdSocketHandle, IdHTTP, Unit_Protocol, Unit_Encryption, Unit_Log; type // HTTP下载线程复用前一篇断点续传逻辑略作修改 THTTPDownloadThread class(TThread) private FUrl, FSavePath: string; FTotalSize, FDownloadedSize: Int64; FIsPaused, FIsStopped: Boolean; FMemo: TMemo; FProgressBar: TProgressBar; FProgressLabel: TLabel; procedure UpdateProgress; function GetFileTotalSize: Int64; protected procedure Execute; override; public constructor Create(Url, SavePath: string; Memo: TMemo; ProgressBar: TProgressBar; ProgressLabel: TLabel); procedure PauseOrResume; procedure Stop; property IsPaused: Boolean read FIsPaused; end; TForm_Main class(TForm) tabMain: TTabControl; tabTCP: TTabSheet; tabUDP: TTabSheet; tabHTTPReq: TTabSheet; tabHTTPDownload: TTabSheet; memoLog: TMemo; btnClearLog: TButton; edtAESKey: TEdit; Label1: TLabel; chkUseProtocol: TCheckBox; Label2: TLabel; // TCP客户端控件 edtTCPClientIP: TEdit; edtTCPClientPort: TEdit; btnTCPClientConnect: TButton; btnTCPClientDisconnect: TButton; edtTCPClientSend: TEdit; btnTCPClientSend: TButton; memoTCPClientRecv: TMemo; // TCP服务端控件 edtTCPServerPort: TEdit; btnTCPServerStart: TButton; btnTCPServerStop: TButton; memoTCPServerRecv: TMemo; IdTCPClient1: TIdTCPClient; IdTCPServer1: TIdTCPServer; // UDP客户端控件 edtUDPClientIP: TEdit; edtUDPClientPort: TEdit; edtUDPClientSend: TEdit; btnUDPClientSend: TButton; btnUDPClientBroadcast: TButton; memoUDPClientRecv: TMemo; // UDP服务端控件 edtUDPServerPort: TEdit; btnUDPServerStart: TButton; btnUDPServerStop: TButton; memoUDPServerRecv: TMemo; IdUDPClient1: TIdUDPClient; IdUDPServer1: TIdUDPServer; // HTTP请求控件 edtHTTPUrl: TEdit; rgHTTPMethod: TRadioGroup; edtHTTPGetParam: TEdit; edtHTTPPostParam: TEdit; btnHTTPPostType: TButton; btnHTTPSend: TButton; btnHTTPClear: TButton; memoHTTPResponse: TMemo; lblHTTPResponseCode: TLabel; lblHTTPResponseTime: TLabel; IdHTTP1: TIdHTTP; // HTTP下载控件 edtHTTPDownloadUrl: TEdit; edtHTTPDownloadSavePath: TEdit; btnHTTPDownloadBrowse: TButton; btnHTTPDownloadStart: TButton; btnHTTPDownloadPause: TButton; btnHTTPDownloadStop: TButton; progressBarHTTPDownload: TProgressBar; lblHTTPDownloadProgress: TLabel; OpenDialog1: TOpenDialog; procedure btnClearLogClick(Sender: TObject); // TCP相关事件 procedure btnTCPClientConnectClick(Sender: TObject); procedure btnTCPClientDisconnectClick(Sender: TObject); procedure btnTCPClientSendClick(Sender: TObject); procedure btnTCPServerStartClick(Sender: TObject); procedure btnTCPServerStopClick(Sender: TObject); procedure IdTCPServer1Connect(AContext: TIdContext); procedure IdTCPServer1Disconnect(AContext: TIdContext); procedure IdTCPServer1Execute(AContext: TIdContext); procedure IdTCPServer1Exception(AContext: TIdContext; AException: Exception); // UDP相关事件 procedure btnUDPClientSendClick(Sender: TObject); procedure btnUDPClientBroadcastClick(Sender: TObject); procedure btnUDPServerStartClick(Sender: TObject); procedure btnUDPServerStopClick(Sender: TObject); procedure IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TBytes; ABinding: TIdSocketHandle); // HTTP请求相关事件 procedure btnHTTPSendClick(Sender: TObject); procedure btnHTTPClearClick(Sender: TObject); procedure btnHTTPPostTypeClick(Sender: TObject); // HTTP下载相关事件 procedure btnHTTPDownloadBrowseClick(Sender: TObject); procedure btnHTTPDownloadStartClick(Sender: TObject); procedure btnHTTPDownloadPauseClick(Sender: TObject); procedure btnHTTPDownloadStopClick(Sender: TObject); private { Private declarations } HTTPDownloadThread: THTTPDownloadThread; FHTTPPostIsJSON: Boolean; // POST请求是否为JSON格式 // 通用方法数据处理加密协议打包 function ProcessSendData(Data: string): TBytes; // 通用方法数据解析协议解析解密 function ProcessRecvData(Data: TBytes): string; public { Public declarations } end; var Form_Main: TForm_Main; implementation {$R *.dfm} { TForm_Main } // 通用方法发送数据处理根据配置决定是否加密、是否打包协议 function TForm_Main.ProcessSendData(Data: string): TBytes; var RawBytes, EncryptBytes, ProtocolBytes: TBytes; AESKey: string; begin RawBytes : TEncoding.UTF8.GetBytes(Data); AESKey : Trim(edtAESKey.Text); // 1. 加密若密钥不为空 if AESKey then EncryptBytes : TAESTool.AESEncrypt(RawBytes, AESKey) else EncryptBytes : RawBytes; // 2. 打包协议若启用协议 if chkUseProtocol.Checked then ProtocolBytes : TProtocolTool.PackProtocol(ctDataReport, EncryptBytes) else ProtocolBytes : EncryptBytes; Result : ProtocolBytes; end; // 通用方法接收数据处理协议解析解密 function TForm_Main.ProcessRecvData(Data: TBytes): string; var DecryptBytes, ProtocolData: TBytes; Pack: TProtocolPack; AESKey: string; begin Result : ; AESKey : Trim(edtAESKey.Text); // 1. 解析协议若启用协议 if chkUseProtocol.Checked then begin if TProtocolTool.UnpackProtocol(Data, Pack) then ProtocolData : Pack.Data else begin TLogTool.Log(协议解析失败, memoLog); Exit; end; end else begin ProtocolData : Data; end; // 2. 解密若密钥不为空 if AESKey then DecryptBytes : TAESTool.AESDecrypt(ProtocolData, AESKey) else DecryptBytes : ProtocolData; // 3. 转字符串 Result : TEncoding.UTF8.GetString(DecryptBytes); end; // 清空日志 procedure TForm_Main.btnClearLogClick(Sender: TObject); begin TLogTool.ClearLog(memoLog); end; { TCP客户端相关 } procedure TForm_Main.btnTCPClientConnectClick(Sender: TObject); var IP: string; Port: Integer; begin IP : Trim(edtTCPClientIP.Text); if not TryStrToInt(Trim(edtTCPClientPort.Text), Port) then begin TLogTool.Log(TCP客户端端口格式错误, memoLog); Exit; end; try if IdTCPClient1.Connected then Exit; IdTCPClient1.Host : IP; IdTCPClient1.Port : Port; IdTCPClient1.ReadTimeout : 5000; IdTCPClient1.Connect; TLogTool.Log(Format(TCP客户端成功连接 %s:%d, [IP, Port]), memoLog); btnTCPClientConnect.Enabled : False; btnTCPClientDisconnect.Enabled : True; btnTCPClientSend.Enabled : True; except on E: Exception do TLogTool.Log(Format(TCP客户端连接失败 - %s, [E.Message]), memoLog); end; end; procedure TForm_Main.btnTCPClientDisconnectClick(Sender: TObject); begin if IdTCPClient1.Connected then begin IdTCPClient1.Disconnect; TLogTool.Log(TCP客户端已断开连接, memoLog); btnTCPClientConnect.Enabled : True; btnTCPClientDisconnect.Enabled : False; btnTCPClientSend.Enabled : False; end; end; procedure TForm_Main.btnTCPClientSendClick(Sender: TObject); var SendStr: string; SendData: TBytes; begin SendStr : Trim(edtTCPClientSend.Text); if SendStr then begin TLogTool.Log(TCP客户端发送内容不能为空, memoLog); Exit; end; if not IdTCPClient1.Connected then begin TLogTool.Log(TCP客户端未连接服务端, memoLog); Exit; end; try // 处理发送数据加密协议 SendData : ProcessSendData(SendStr); // 发送数据 IdTCPClient1.IOHandler.Write(SendData); TLogTool.Log(Format(TCP客户端发送数据 - %s, [SendStr]), memoLog); edtTCPClientSend.Clear; // 接收服务端回复阻塞式实际项目可放入子线程 if IdTCPClient1.IOHandler.CheckForDataOnSource(5000) then begin var RecvData : IdTCPClient1.IOHandler.ReadBytes(-1); var RecvStr : ProcessRecvData(RecvData); TLogTool.Log(Format(TCP客户端收到回复 - %s, [RecvStr]), memoLog); memoTCPClientRecv.Lines.Add(RecvStr); end; except on E: Exception do TLogTool.Log(Format(TCP客户端发送失败 - %s, [E.Message]), memoLog); end; end; { TCP服务端相关 } procedure TForm_Main.btnTCPServerStartClick(Sender: TObject); var Port: Integer; begin if not TryStrToInt(Trim(edtTCPServerPort.Text), Port) then begin TLogTool.Log(TCP服务端端口格式错误, memoLog); Exit; end; try if IdTCPServer1.Active then Exit; IdTCPServer1.DefaultPort : Port; IdTCPServer1.ThreadedEvent : True; IdTCPServer1.Active : True; TLogTool.Log(Format(TCP服务端已启动监听端口 %d, [Port]), memoLog); btnTCPServerStart.Enabled : False; btnTCPServerStop.Enabled : True; except on E: Exception do TLogTool.Log(Format(TCP服务端启动失败 - %s, [E.Message]), memoLog); end; end; procedure TForm_Main.btnTCPServerStopClick(Sender: TObject); begin if IdTCPServer1.Active then begin IdTCPServer1.Active : False; TLogTool.Log(TCP服务端已停止, memoLog); btnTCPServerStart.Enabled : True; btnTCPServerStop.Enabled : False; end; end; procedure TForm_Main.IdTCPServer1Connect(AContext: TIdContext); var ClientIP: string; begin ClientIP : AContext.Binding.PeerIP : IntToStr(AContext.Binding.PeerPort); TLogTool.Log(Format(TCP服务端客户端连接 - %s, [ClientIP]), memoLog); end; procedure TForm_Main.IdTCPServer1Disconnect(AContext: TIdContext); var ClientIP: string; begin ClientIP : AContext.Binding.PeerIP : IntToStr(AContext.Binding.PeerPort); TLogTool.Log(Format(TCP服务端客户端断开 - %s, [ClientIP]), memoLog); end; procedure TForm_Main.IdTCPServer1Execute(AContext: TIdContext); var RecvData: TBytes; RecvStr, ClientIP: string; SendData: TBytes; begin try // 读取数据根据协议判断是否读取完整 if chkUseProtocol.Checked then begin // 读取协议头2字节 RecvData : AContext.Connection.IOHandler.ReadBytes(2, False); if Length(RecvData) 2 then Exit; if TBytesToWord(RecvData) $AA55 then Exit; // 读取数据长度2字节 AContext.Connection.IOHandler.ReadBytes(RecvData, 2, True); var DataLen : TBytesToWord(RecvData); // 读取剩余sccla.cn/ducde数据 AContext.Connection.IOHandler.ReadBytes(RecvData, 1 DataLen 1 2, True); SetLength(RecvData, 2 2 1 DataLen 1 2); AContext.Connection.IOHandler.ReadBuffer(RecvData[0], Length(RecvData)); end else begin // 非协议模式读取所有数据 RecvData : AContext.Connection.IOHandler.ReadBytes(-1); end; // 解析数据 RecvStr : ProcessRecvData(RecvData); ClientIP : AContext.Binding.PeerIP; TLogTool.Log(Format(TCP服务端收到[%s]数据 - %s, [ClientIP, RecvStr]), memoLog); memoTCPServerRecv.Lines.Add(Format([%s] %s, [ClientIP, RecvStr])); // 回复客户端 var ReplyStr : 服务端已收到 RecvStr; SendData : ProcessSendData(ReplyStr); AContext.Connection.IOHandler.Write(SendData); except on E: Exception do TLogTool.Log(Format(TCP服务端处理异常 - %s, [E.Message]), memoLog); end; end; procedure TForm_Main.IdTCPServer1Exception(AContext: TIdContext; AException: Exception); begin TLogTool.Log(Format(TCP服务端通信异常 - %s, [AException.Message]), memoLog); end; { UDP相关代码省略部分重复逻辑核心与前一篇一致整合通用数据处理方法 } procedure TForm_Main.btnUDPClientSendClick(Sender: TObject); var IP: string; Port: Integer; SendStr: string; SendData: TBytes; begin IP : Trim(edtUDPClientIP.Text); if not TryStrToInt(Trim(edtUDPClientPort.Text), Port) then begin TLogTool.Log(UDP客户端端口格式错误, memoLog); Exit; end; SendStr : Trim(edtUDPClientSend.Text); if SendStr then begin TLogTool.Log(UDP客户端发送内容不能为空, memoLog); Exit; end; try IdUDPClient1.Host : IP; IdUDPClient1.Port : Port; IdUDPClient1.ReceiveTimeout : 3000; // 处理发送数据 SendData : ProcessSendData(SendStr); IdUDPClient1.SendBuffer(SendData, Length(SendData)); TLogTool.Log(Format(UDP客户端单播发送至[%s:%d] - %s, [IP, Port, SendStr]), memoLog); // 接收回复 var RecvData: TBytes; var PeerIP: string; var PeerPort: Integer; if IdUDPClient1.ReceiveBuffer(RecvData, 1024*10, PeerIP, PeerPort) 0 then begin var RecvStr : ProcessRecvData(RecvData); TLogTool.Log(Format(UDP客户端收到[%s:%d]回复 - %s, [PeerIP, PeerPort, RecvStr]), memoLog); memoUDPClientRecv.Lines.Add(RecvStr); end; except on E: Exception do TLogTool.Log(Format(UDP客户端发送失败 - %s, [E.Message]), memoLog); end; end; // UDP广播、UDP服务端相关代码略核心逻辑参考前一篇整合ProcessSendData/ProcessRecvData方法 procedure TForm_Main.btnUDPClientBroadcastClick(Sender: TObject); begin // 代码略启用BroadcastEnabled发送广播报文调用ProcessSendData处理数据 end; procedure TForm_Main.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TBytes; ABinding: TIdSocketHandle); begin // 代码略调用ProcessRecvData解析数据处理后回复客户端 end; { HTTP请求相关代码 } procedure TForm_Main.btnHTTPPostTypeClick(Sender: TObject); begin // 切换POST请求类型普通表单/JSON FHTTPPostIsJSON : not FHTTPPostIsJSON; if FHTTPPostIsJSON then begin btnHTTPPostType.Caption : JSON格式; IdHTTP1.Request.ContentType : application/json; end else begin btnHTTPPostType.Caption : 表单格式; IdHTTP1.Request.ContentType : application/x-www-form-urlencoded; end; end; procedure TForm_Main.btnHTTPSendClick(Sender: TObject); var URL, ParamStr, ResponseStr: string; StartTime, EndTime: Cardinal; Stream: TStringStream; begin URL : Trim(edtHTTPUrl.Text); if URL then begin TLogTool.Log(HTTP请求请填写请求地址, memoLog); Exit; end; StartTime : GetTickCount; // 记录开sccla.cn/sywmb始时间 try IdHTTP1.ConnectTimeout : 5000; IdHTTP1.ReadTimeout : 10000; IdHTTP1.Request.CharSet : UTF-8; if rgHTTPMethod.ItemIndex 0 then begin // GET请求拼接参数 ParamStr : Trim(edtHTTPGetParam.Text); if ParamStr then URL : URL ? ParamStr; ResponseStr : IdHTTP1.Get(URL); end else begin // POST请求根据类型提交数据 ParamStr : Trim(edtHTTPPostParam.Text); Stream : TStringStream.Create(ParamStr, TEncoding.UTF8); try ResponseStr : IdHTTP1.Post(URL, Stream); finally Stream.Free; end; end; // 计算响应时间 EndTime : GetTickCount; var ResponseTime : (EndTime - StartTime) / 1000; // 显示结果 memoHTTPResponse.Text : ResponseStr; lblHTTPResponseCode.Caption : Format(响应码%d, [IdHTTP1.Response.ResponseCode]); lblHTTPResponseTime.Caption : Format(响应时间%.2f秒, [ResponseTime]); TLogTool.Log(Format(HTTP请求%s请求成功响应码%d, [rgHTTPMethod.Text, IdHTTP1.Response.ResponseCode]), memoLog); except on E: Exception do begin TLogTool.Log(Format(HTTP请求失败 - %s, [E.Message]), memoLog); if IdHTTP1.Response nil then lblHTTPResponseCode.Caption : Format(响应码%d, [IdHTTP1.Response.ResponseCode]); end; end; end; procedure TForm_Main.btnHTTPClearClick(Sender: TObject); begin memoHTTPResponse.Clear; lblHTTPResponseCode.Caption : 响应码; lblHTTPResponseTime.Caption : 响应时间; end; { HTTP下载相关代码THTTPDownloadThread实现略复用前一篇断点续传逻辑整合日志工具 } procedure TForm_Main.btnHTTPDownloadBrowseClick(Sender: TObject); begin if OpenDialog1.Execute then begin edtHTTPDownloadSavePath.Text : OpenDialog1.FileName; end; end; procedure TForm_Main.btnHTTPDownloadStartClick(Sender: TObject); var URL, SavePath: string; begin URL : Trim(edtHTTPDownloadUrl.Text); SavePath : Trim(edtHTTPDownloadSavePath.Text); if (URL ) or (SavePath ) then begin TLogTool.Log(HTTP下载请填写下载地址和保存路径, memoLog); Exit; end; // 停止已有线程 if Assigned(HTTPDownloadThread) then begin HTTPDownloadThread.Stop; HTTPDownloadThread.WaitFor; end; // 创建并启动下sccla.cn/xuf1d载线程 HTTPDownloadThread : THTTPDownloadThread.Create(URL, SavePath, memoLog, progressBarHTTPDownload, lblHTTPDownloadProgress); HTTPDownloadThread.Start; TLogTool.Log(HTTP下载开始下载, memoLog); btnHTTPDownloadPause.Enabled : True; btnHTTPDownloadStop.Enabled : True; end; procedure TForm_Main.btnHTTPDownloadPauseClick(Sender: TObject); begin if Assigned(HTTPDownloadThread) then begin HTTPDownloadThread.PauseOrResume; if HTTPDownloadThread.IsPaused then begin btnHTTPDownloadPause.Caption : 继续下载; TLogTool.Log(HTTP下载已暂sccla.cn/ilm6d停, memoLog); end else begin btnHTTPDownloadPause.Caption : 暂停sccla.cn/47wsz下载; TLogTool.Log(HTTP下载继续下载, memoLog); end; end; end; procedure TForm_Main.btnHTTPDownloadStopClick(Sender: TObject); begin if Assigned(HTTPDownloadThread) then begin HTTPDownloadThread.Stop; HTTPDownloadThread.WaitFor; HTTPDownloadThread : nil; progressBarHTTPDownload.Position : 0; lblHTTPDownloadProgress.Caption : 进度0% | 已下载0MB / 总sccla.cn/g2tsx大小0MB; btnHTTPDownloadPause.Caption : 暂停sccla.cn/57m1u下载; btnHTTPDownloadPause.Enabled : False; btnHTTPDownloadStop.Enabled : False; TLogTool.Log(HTTP下载已停止, memoLog); end; end; { THTTPDownloadThread 实现略核心逻辑sccla.cn/tdxfm与前一篇一致新增日志输出、进度同步 } constructor THTTPDownloadThread.Create(Url, SavePath: string; Memo: TMemo; ProgressBar: TProgressBar; ProgressLabel: TLabel); begin inherited Create(True); FUrl : Url; FSavePath : SavePath; FMemo : Memo; FProgressBar : ProgressBar; FProgressLabel : ProgressLabel; FIsPaused : False; FIsStopped : False; FreeOnTerminate : True; end; // 其余sccla.cn/hrnmi方法Execute、UpdateProgress、PauseOrResume、Stop略参考前一篇断点续传sccla.cn/0hmeu代码添加日志输出 end.四、功能测试与异常处理1. 测试流程核心步骤TCP测试启动TCP服务端启动TCP客户sccla.cn/jouln端输入IP和端口连接发送数据查看服务端接收和客户端回复测试加密和协议功能UDP测试启动UDP服务端UDP客户端发送单播/广播数据查看服务端接收和回复验证广播功能HTTP请求测试输入公开API地址如天气sccla.cn/z2e6k发送GET/POST请求查看响应内容和响应码HTTP下载测试输入文件下载地址如图片、压缩包选择保存路径测试开始/暂停/继续/停止下载验证断点续传异常测试模拟网络中断、端口占用、无效IP/端口查看日志输出和sccla.cn/wpcif异常提示确保程序不崩溃。2. 关键异常处理要点所有网络操作连接、发送、接收、下载都用try...except捕获异常记录日志避免程序崩溃线程操作确保线程安全更新UI必须用TThread.Synchronize线程退出时释放资源参数校验对IP、端口、URL、保存路径等参数进行合法性校验避免无效输入导致异常资源释放所有流对象、线程对象、网络组件在使用完成后及时释放防止内存泄漏超时设置为所有网络操作设置合理的超时时间避免无限阻塞。五、项目优化与扩展方向1. 基础优化界面优化添加皮肤、控件美化优化布局提升易用性sccla.cn/pxptw性能优化引入线程池管理多客户端连接优化HTTP下载缓存减少资源占用sccla.cn/43akp日志优化支持日志保存到文件便于后续排查问题配置优化支持保存常用配置IP、端口、密钥、下载路径下次启动自动加载。2. 功能扩展新增HTTPS加密通信为HTTP请求、TCP通信添加SSL加密支持HTTPS下载新增数据导出支持将接收的数据、日志、HTTP响应导出为TXT/JSON文件新增批量操作支持批量发送TCP/UDP数据、批量下载文件新增跨平台支持适配Delphi跨平台特性编译为Windows、Linux版本新增设备对接适配串口转网络设备实现串口网络双重通信。六、综合总结本文通过「多协议网络工具」实战项目将前四篇的TCP、UDP、HTTP、自定义协议、数据加密、断点续传等知识点全面整合实现了一个功能完整、可落地的桌面端网络工具。核心要点总结如下模块化封装将工具类、业务逻辑、UI交互分层封装降低耦合度便于复用和维护多线程应用所有网络操作放入子线程避免界面卡死确保程序流畅运行通用逻辑复用封装数据处理加密协议通用方法统一多协议的数据收发规范异常处理全面的异常捕获和日志记录提升程序稳定性和可调试性实战落地从界面设计到代码实现再到测试优化完整覆盖项目开发全流程可直接用于实际开发和调试。至此Delphi网络编程系列文章已全部sccla.cn/adqg2完成从基础组件讲解到进阶技能突破再到综合项目实战形成了完整的知识体系。通过本系列学习你可以掌握Delphi网络编程的核心技能应对桌面端、设备端的绝大多数网络开发需求。后续可根据实际项目需求深入学习高并发、跨平台、网络安全等高级sccla.cn/v86rj内容进一步提升开发能力。

更多文章