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

如何在Delphi Tokyo 10.2中为IdTCPServer分配IP地址?

问题分析与解决方案

我看了你的Delphi Indy TCP服务器代码,这里有几个关键问题会导致程序不稳定、异常甚至崩溃,我来一步步帮你修正:

1. 重复创建组件的错误

你在FormCreate里手动调用了IdTCPServer1:=IdTCPServer1.Create(nil);,但如果这个组件是你在设计时拖到窗体上的,这就会导致重复创建组件,引发内存泄漏或者后续操作的异常。

修正方案:移除手动创建的代码,直接设置组件属性即可:

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 删掉 IdTCPServer1:=IdTCPServer1.Create(nil); 这一行
  IdTCPServer1.DefaultPort:=50000;
  IdTCPServer1.OnExecute:=IdTCPServer1Execute;
  IdTCPServer1.Active:=true;
end;

2. 跨线程操作VCL控件的风险

Indy的OnConnect和OnExecute事件都是在工作线程中触发的,直接在这些事件里操作Memo1或者调用ShowMessage(VCL控件)属于跨线程操作,会导致线程不安全,大概率引发程序崩溃或UI异常。

解决这个问题需要用TThread.Synchronize(同步)或者TThread.Queue(异步)把UI操作委托给主线程执行:

修正OnConnect事件

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
  PeerIP: string;
begin
  PeerIP := AContext.Connection.Socket.Binding.PeerIP;
  // 用Synchronize把UI操作同步到主线程
  TThread.Synchronize(nil, procedure
  begin
    Memo1.Lines.Add('客户端连接: ' + PeerIP);
  end);
end;

修正OnExecute事件

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  ReceivedMsg: string;
begin
  try
    // 给ReadLn设置超时,避免线程无限阻塞
    AContext.Connection.Socket.ReadTimeout := 5000; // 5秒超时
    ReceivedMsg := AContext.Connection.Socket.ReadLn();
    if Trim(ReceivedMsg) <> '' then
    begin
      // 用Queue异步更新UI,避免阻塞工作线程
      TThread.Queue(nil, procedure
      begin
        Memo1.Lines.Add('收到来自 ' + AContext.Connection.Socket.Binding.PeerIP + ' 的消息: ' + ReceivedMsg);
        ShowMessage('收到新消息: ' + ReceivedMsg);
      end);
    end;
  except
    on E: Exception do
    begin
      // 忽略超时异常,只记录其他错误
      if not(E is EIdReadTimeout) then
      begin
        TThread.Synchronize(nil, procedure
        begin
          Memo1.Lines.Add('连接异常 (' + AContext.Connection.Socket.Binding.PeerIP + '): ' + E.Message);
        end);
      end;
      AContext.Connection.Disconnect;
    end;
  end;
end;

3. 额外优化建议

  • 建议在窗体销毁时关闭服务器,确保资源正确释放:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if IdTCPServer1.Active then
    IdTCPServer1.Active := False;
end;
  • 尽量避免在工作线程中使用ShowMessage这类阻塞弹窗,优先用Memo记录消息,减少对服务器并发能力的影响。

完整修正后的代码

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    IdTCPServer1: TIdTCPServer;
    Memo1: TMemo;
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure FormCreate(Sender: TObject);
    procedure IdTCPServer1Connect(AContext: TIdContext);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  IdTCPServer1.DefaultPort := 50000;
  IdTCPServer1.OnExecute := IdTCPServer1Execute;
  IdTCPServer1.Active := True;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if IdTCPServer1.Active then
    IdTCPServer1.Active := False;
end;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
  PeerIP: string;
begin
  PeerIP := AContext.Connection.Socket.Binding.PeerIP;
  TThread.Synchronize(nil, procedure
  begin
    Memo1.Lines.Add('客户端已连接: ' + PeerIP);
  end);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  ReceivedMsg: string;
begin
  try
    AContext.Connection.Socket.ReadTimeout := 5000;
    ReceivedMsg := AContext.Connection.Socket.ReadLn();
    if Trim(ReceivedMsg) <> '' then
    begin
      TThread.Queue(nil, procedure
      begin
        Memo1.Lines.Add('[' + AContext.Connection.Socket.Binding.PeerIP + '] 发来消息: ' + ReceivedMsg);
        ShowMessage('收到新消息: ' + ReceivedMsg);
      end);
    end;
  except
    on E: Exception do
    begin
      if not(E is EIdReadTimeout) then
      begin
        TThread.Synchronize(nil, procedure
        begin
          Memo1.Lines.Add('[' + AContext.Connection.Socket.Binding.PeerIP + '] 连接异常: ' + E.Message);
        end);
      end;
      AContext.Connection.Disconnect;
    end;
  end;
end;

end.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:28:15