TIdTCPServer.OnExecute事件陷入无限循环的原因排查求助
TIdTCPServer.OnExecute无限循环的原因与修复方案
问题根源
OnExecute事件的执行机制
TIdTCPServer的每个客户端连接对应独立工作线程,该线程会持续循环调用OnExecute事件处理程序,直到连接断开。你的代码中,当输入缓冲区为空时DoOnIndyExecute直接返回,线程会立刻再次调用该方法,导致高频空转,看起来像无限循环,同时占用大量CPU资源。错误的缓冲区判断逻辑
你用InputBufferIsEmpty判断是否读取数据,但这个判断是瞬时的——如果当前无数据,方法直接退出,线程马上再次执行,形成无意义的循环。正确做法是让线程在无数据时阻塞等待,而非反复检查。线程不安全的UI操作
Memo1.Lines.Add在工作线程中直接调用VCL控件方法,VCL控件并非线程安全,这可能导致UI异常或程序崩溃,也会间接加剧循环的异常表现。未正确保护共享变量
你创建了FCS临界区,但IncrementConnectionCount未用它保护FConnectionCount的递增,多线程环境下会导致计数错误。
修复方案
1. 让线程阻塞等待数据
去掉InputBufferIsEmpty判断,直接调用ReadLn——Indy的ReadLn默认会阻塞线程,直到有数据到来或连接断开,线程无数据时会休眠,不会空转循环。若需超时,可指定参数,比如ReadLn(5000)表示等待5秒超时。
2. 线程安全更新UI
使用TThread.Synchronize或TThread.Queue将UI操作同步到主线程执行。
3. 用临界区保护共享变量
修改FConnectionCount时必须进入临界区,避免多线程竞争。
修正后的服务器代码
procedure TForm1.FormCreate(Sender: TObject); begin FConnectionCount := 0; FCS := TCriticalSection.Create; FIdTCPServer := TIdTCPServer.Create(nil); FIdTCPServer.DefaultPort := 50000; FIdTCPServer.MaxConnections := 9000; FIdTCPServer.OnExecute := DoOnIndyExecute; FIdTCPServer.Active := true; end; procedure TForm1.IncrementConnectionCount; begin FCS.Enter; try Inc(FConnectionCount); finally FCS.Leave; end; end; procedure TForm1.DoOnIndyExecute(AContext: TIdContext); var recv, peerIP: string; peerPort: Word; LogText: string; begin try // 阻塞等待数据,可自行设置超时(如ReadLn(5000)) recv := AContext.Connection.IOHandler.ReadLn; IncrementConnectionCount; peerIP := AContext.Binding.PeerIP; peerPort := AContext.Binding.PeerPort; AContext.Connection.IOHandler.WriteLn('Done'); LogText := IntToStr(FConnectionCount) + ' - IP: ' + peerIP + ' Port: ' + IntToStr(peerPort) + ' Message: ' + recv; // 同步到主线程更新UI TThread.Synchronize(nil, procedure begin Memo1.Lines.Add(LogText); end); except on E: Exception do begin // 处理连接异常 TThread.Synchronize(nil, procedure begin Memo1.Lines.Add('Connection error: ' + E.Message); end); // 断开连接,让线程退出循环 AContext.Connection.Disconnect; end; end; end;
额外提示
- 客户端创建大量
TIdTCPClient并保持连接时,注意系统端口限制(默认临时端口范围有限),若需数千级连接,需调整系统TCP参数。 - 客户端的
ReadLn会阻塞直到收到服务器响应,确保服务器能及时处理每个连接请求。
内容的提问来源于stack exchange,提问作者Francesco Esposito
相关产品推荐
相关产品推荐

