Delphi 网络编程实战:TIdTCPClient 与 TIdTCPServer 类深度解析

在 Delphi 开发中,网络通信 是桌面应用、服务端程序、物联网设备交互的核心需求。Indy(Internet Direct)组件库是 Delphi 内置的老牌网络开发工具包,基于阻塞式套接字实现,封装了 TCP、UDP、HTTP 等主流网络协议,其中 TIdTCPClient(TCP 客户端)TIdTCPServer(TCP 服务端) 是实现自定义 TCP 通信的核心类,也是 Delphi 网络编程的基础。

本文将从零讲解这两个核心类的用法、关键属性 / 方法、线程安全机制,并提供完整的客户端 + 服务端通信实战代码。

一、Indy 组件库基础

Indy 是 Delphi 自带的跨平台网络组件库,无需额外安装,直接在组件面板的Indy ClientsIndy Servers分类中调用:

  • TIdTCPClient:客户端组件,用于主动连接服务端、发送 / 接收数据;
  • TIdTCPServer:服务端组件,用于监听端口、接受客户端连接、处理多客户端通信;
  • 核心特性:阻塞式通信(数据收发时会阻塞当前线程,需配合线程避免界面卡死)、支持多客户端连接、内置数据编码 / 解码、异常捕获机制。

适用场景:自定义协议通信、设备控制、内网数据传输、服务端监听等。

二、TIdTCPClient 客户端核心详解

1. 关键属性

表格

属性名 作用
Host 目标服务端的 IP 地址(如 127.0.0.1 本地回环、192.168.1.100 内网 IP)
Port 目标服务端的监听端口(需与服务端一致,范围 1~65535)
Connected 只读属性,判断是否与服务端建立连接(True = 已连接,False = 未连接)
ReadTimeout 数据读取超时时间(毫秒),避免无限阻塞

2. 核心方法

  • Connect:主动连接服务端,失败会抛出异常(需用 try...except 捕获);
  • Disconnect:断开与服务端的连接,释放套接字资源;
  • IOHandler.Write:发送数据(支持字符串、字节流、整数等类型);
  • IOHandler.ReadString:读取指定长度的字符串数据;
  • IOHandler.ReadLn:按行读取数据(以换行符 \n 为结束标记)。

三、TIdTCPServer 服务端核心详解

1. 关键属性

表格

属性名 作用
DefaultPort 服务端监听的端口(客户端需通过此端口连接)
Active 启动 / 停止服务端(True = 启动监听,False = 停止监听)
Bindings 绑定监听的 IP(默认 0.0.0.0 监听所有网卡,可指定内网 IP)
Contexts 存储所有已连接的客户端上下文(用于遍历在线客户端)

2. 核心事件(服务端核心逻辑)

  • OnConnect:客户端成功连接时触发,可记录客户端信息;
  • OnDisconnect:客户端断开连接时触发,清理资源;
  • OnExecute核心事件,客户端发送数据时触发,用于接收 / 处理数据、回复客户端;
  • OnException:捕获通信过程中的异常,避免服务端崩溃。

3. 线程安全机制

TIdTCPServer 内置多线程管理:每一个客户端连接都会分配一个独立线程(TIdContext),所有客户端通信互不干扰,无需手动创建线程,这是 Indy 最实用的特性。

四、实战:Delphi TCP 客户端 + 服务端完整实现

环境准备

  • Delphi 7/XE/10.X 版本(本文以 Delphi 10.4 为例);
  • 新建两个 VCL 工程:TCPClientDemo(客户端)TCPServerDemo(服务端)

第一部分:服务端开发(TCPServerDemo)

1. 界面设计
  • 1 个 TMemo(名称:memoLog,显示日志);
  • 2 个 TButton(btnStart = 启动服务,btnStop = 停止服务);
  • 1 个 TIdTCPServer(名称:IdTCPServer1,拖入界面即可)。
2. 完整代码

delphi

复制代码
unit ServerMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.IdTCPServer,
  IdContext, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPServer;

type
  TForm1 = class(TForm)
    IdTCPServer1: TIdTCPServer;
    memoLog: TMemo;
    btnStart: TButton;
    btnStop: TButton;
    procedure btnStartClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure IdTCPServer1Connect(AContext: TIdContext);
    procedure IdTCPServer1Disconnect(AContext: TIdContext);
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure IdTCPServer1Exception(AContext: TIdContext; AException: Exception);
  private
    { Private declarations }
    procedure Log(Msg: string); // 日志输出方法
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// 日志输出(线程安全,避免界面卡死)
procedure TForm1.Log(Msg: string);
begin
  TThread.Synchronize(nil, procedure
  begin
    memoLog.Lines.Add(FormatDateTime('yyyy-mm-dd hh:MM:ss', Now) + ':' + Msg);
  end);
end;

// 启动服务
procedure TForm1.btnStartClick(Sender: TObject);
begin
  if IdTCPServer1.Active then Exit;
  IdTCPServer1.DefaultPort := 8888; // 监听端口8888
  IdTCPServer1.Active := True;
  Log('服务已启动,监听端口:8888');
end;

// 停止服务
procedure TForm1.btnStopClick(Sender: TObject);
begin
  IdTCPServer1.Active := False;
  Log('服务已停止');
end;

// 客户端连接事件
procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
  ClientIP: string;
begin
  // 获取客户端IP和端口
  ClientIP := AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.PeerPort);
  Log('客户端连接:' + ClientIP);
end;

// 客户端断开事件
procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
var
  ClientIP: string;
begin
  ClientIP := AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.PeerPort);
  Log('客户端断开:' + ClientIP);
end;

// 核心:接收客户端数据并回复
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  RecvStr: string;
  ClientIP: string;
begin
  // 按行读取客户端发送的数据
  RecvStr := AContext.Connection.IOHandler.ReadLn;
  ClientIP := AContext.Binding.PeerIP;

  Log('收到['+ClientIP+']数据:' + RecvStr);

  // 回复客户端
  AContext.Connection.IOHandler.WriteLn('服务端已收到:' + RecvStr);
end;

// 异常捕获
procedure TForm1.IdTCPServer1Exception(AContext: TIdContext; AException: Exception);
begin
  Log('通信异常:' + AException.Message);
end;

end.

第二部分:客户端开发(TCPClientDemo)

1. 界面设计
  • 1 个 TMemo(memoLog,显示通信日志);
  • 1 个 TEdit(edtSend,输入发送内容);
  • 3 个 TButton(btnConnect = 连接服务端,btnSend = 发送数据,btnDisconnect = 断开连接);
  • 1 个 TIdTCPClient(IdTCPClient1,拖入界面)。
2. 完整代码

delphi

复制代码
unit ClientMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent,
  IdComponent, IdTCPConnection, IdTCPClient;

type
  TForm1 = class(TForm)
    IdTCPClient1: TIdTCPClient;
    memoLog: TMemo;
    edtSend: TEdit;
    btnConnect: TButton;
    btnSend: TButton;
    btnDisconnect: TButton;
    procedure btnConnectClick(Sender: TObject);
    procedure btnSendClick(Sender: TObject);
    procedure btnDisconnectClick(Sender: TObject);
  private
    { Private declarations }
    procedure Log(Msg: string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// 日志输出
procedure TForm1.Log(Msg: string);
begin
  memoLog.Lines.Add(FormatDateTime('yyyy-mm-dd hh:MM:ss', Now) + ':' + Msg);
end;

// 连接服务端
procedure TForm1.btnConnectClick(Sender: TObject);
begin
  if IdTCPClient1.Connected then Exit;
  try
    IdTCPClient1.Host := '127.0.0.1'; // 服务端IP(本地测试用回环地址)
    IdTCPClient1.Port := 8888;        // 服务端端口
    IdTCPClient1.ReadTimeout := 5000; // 超时5秒
    IdTCPClient1.Connect;
    Log('成功连接服务端');
  except
    on E: Exception do
      Log('连接失败:' + E.Message);
  end;
end;

// 发送数据
procedure TForm1.btnSendClick(Sender: TObject);
var
  SendStr, RecvStr: string;
begin
  if not IdTCPClient1.Connected then
  begin
    Log('未连接服务端');
    Exit;
  end;

  if Trim(edtSend.Text) = '' then
  begin
    Log('发送内容不能为空');
    Exit;
  end;

  try
    SendStr := edtSend.Text;
    // 发送数据(按行发送,与服务端ReadLn对应)
    IdTCPClient1.IOHandler.WriteLn(SendStr);
    Log('发送数据:' + SendStr);

    // 读取服务端回复
    RecvStr := IdTCPClient1.IOHandler.ReadLn;
    Log('收到回复:' + RecvStr);
  except
    on E: Exception do
      Log('发送失败:' + E.Message);
  end;
end;

// 断开连接
procedure TForm1.btnDisconnectClick(Sender: TObject);
begin
  if IdTCPClient1.Connected then
  begin
    IdTCPClient1.Disconnect;
    Log('已断开服务端连接');
  end;
end;

end.

tm0.cn/gokdl
tm0.cn/gtzo7
tm0.cn/ng6bi
tm0.cn/wm7oe
tm0.cn/hmax3
tm0.cn/uxune

五、运行测试步骤

  1. 先编译运行tm0.cn/hmax3服务端程序 ,点击【启动服务】,日志显示服务已启动,监听端口:8888
  2. 再编译运行tm0.cn/uxune客户端程序 ,点击【连接服务端】,日志显示成功连接服务端
  3. 客户端输入内容(如Hello Delphi TCP),点击【发送数据】;
  4. 服务端会收到客户端数据并回复,客户端同时显示服务端的回复信息;
  5. 测试多客户端:打开多个客户端程序,同时连接服务端,服务端可正常处理所有客户端通信。

六、关键注意事项

  1. 端口占用 :确保 8888 端口未被其他程序占用,可在 cmd 中用 netstat -ano 查看;
  2. 防火墙:内网通信时,关闭服务端防火墙或放行 8888 端口;
  3. 阻塞问题 :客户端数据收发会阻塞主线程,正式项目需将通信逻辑放入子线程,避免界面卡死;
  4. 数据编码 :传输中文时,需指定编码(如 IdTCPClient1.IOHandler.DefStringEncoding := TEncoding.UTF8),避免乱码;
  5. 异常处理:网络通信必须捕获异常(断开、超时、网络错误),保证程序稳定性。

七、扩展与进阶

  • UDP 通信:Indy 提供 TIdUDPClient/TIdUDPServer,用法与 TCP 类似,适用于实时性高、不要求可靠性的场景;
  • 数据分包:大数据传输时,需自定义协议分包发送(如添加数据长度、校验位);
  • SSL 加密:Indy 支持 TIdSSLIOHandlerSocketOpenSSL 实现加密通信,适用于敏感数据传输;
  • HTTP 通信:TIdHTTP 组件快速实现 GET/POST 请求,对接 Web API。

总结

TIdTCPClient 和 TIdTCPServer 是 Delphi 网络编程的基石 ,依托 Indy 组件库的封装,无需深入底层套接字编程,即可快速实现稳定的 TCP 通信。本文的实战代码可直接用于项目开发,核心掌握连接、收发数据、事件处理、异常捕获四大要点tm0.cn/dltba就能应对绝大多数 Delphi 网络开发需求。

对于新手而言,先吃透 TCP 基础通信,再逐步扩展 UDP、HTTP、SSL 等高级功能,是学习 Delphi 网络编程的最佳路径。

相关推荐
TeDi TIVE2 小时前
Spring Cloud Gateway
java
froginwe112 小时前
CSS 图像拼合技术
开发语言
计算机安禾2 小时前
【数据结构与算法】第22篇:线索二叉树(Threaded Binary Tree)
c语言·开发语言·数据结构·学习·算法·链表·visual studio code
:mnong3 小时前
Superpowers 项目设计分析
java·c语言·c++·python·c#·php·skills
lUie INGA3 小时前
rust web框架actix和axum比较
前端·人工智能·rust
a里啊里啊3 小时前
测试开发面试题
开发语言·chrome·python·xpath
豆沙糕3 小时前
Python异步编程从入门到实战:结合RAG流式回答全解析
开发语言·python·面试
信奥胡老师3 小时前
P1255 数楼梯
开发语言·数据结构·c++·学习·算法
A.A呐3 小时前
【C++第二十一章】set与map封装
开发语言·c++