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

升级到C++Builder 11后TIdTCPServer的Execute事件不触发如何解决

问题现象

原有代码在CBuilder 10.3 Rio版本中可正常实现跨网络文件流传输,升级到CBuilder 11 Alexandria版本后出现以下异常:

  • fileStreamerExecute() 回调函数从未被触发
  • 指定路径下可生成目标文件,但文件长度为0且持续处于占用状态,所有打开该文件的操作都会失败
//---------------------------------------------------------------------------
void Tdata::stream_file(String path, Tstream_dir direction)
{
  _stream_path = path;
  _stream_dir = direction;
  if (_fs)
    delete _fs;
  if (_stream_dir == sdIn)
    _fs = new TFileStream(_stream_path, fmCreate | fmShareDenyNone);
  else
    _fs = new TFileStream(_stream_path, fmOpenRead | fmShareDenyNone);
  fileStreamer->DefaultPort = 9965;
  fileStreamer->Active = true;
}
//---------------------------------------------------------------------------
void __fastcall Tdata::fileStreamerExecute(TIdContext *AContext)
{
  if (_stream_dir == sdIn)
  {
    try
    {
      _fs->Position = 0;
      AContext->Connection->IOHandler->ReadStream(_fs, -1, true);
    }
    __finally
    {
        delete _fs;
        _fs = 0;
    }
    AContext->Connection->Disconnect();
  }
  else
  {
    try
    {
      AContext->Connection->IOHandler->Write(_fs);
    }
    __finally
    {
        delete _fs;
        _fs = 0;
    }
    AContext->Connection->Disconnect();
  }  
}

// ---------------------------------------------------------------------------
__fastcall TstartForm::TstartForm(TComponent* Owner) : TForm(Owner)
{
  char hostname[256];
  String host_ip = "";
  _progressForm = 0;
  if (gethostname(hostname, 256) == 0) {
    hostent *host = gethostbyname(hostname);
    if (host) {
      char *addr = host->h_addr;
      if (addr) {
        host_ip = String(inet_ntoa(*(in_addr*) addr));
        // returns "192.168.180.1" from VMWare network adaptor
        // hard code to correct value for testing
        host_ip = "192.168.1.226"; 
      }
    }
  }
}
根因分析

问题出在本地IP获取逻辑:
旧代码使用WinSock原生API gethostbyname 获取本地IP,该接口在多网卡环境(存在VMware虚拟网卡、VPN网卡等)下,返回的第一个IP并非实际用于业务通信的物理网卡IP。C++Builder 11集成的Indy组件对套接字绑定、连接校验的逻辑做了更新,若监听/连接使用的IP与实际业务网卡不匹配,客户端连接无法被正确分发到OnExecute事件回调。而已经创建的TFileStream因为回调未触发,__finally块中的资源释放逻辑永远不会执行,导致文件一直被占用、没有写入内容。

修复方案

改用Indy内置接口获取本地IP即可解决问题:

初步修复版本

__fastcall TstartForm::TstartForm(TComponent* Owner) : TForm(Owner)
{
  _progressForm = 0;
  String host_ip = L"";
  TIdStackWindows* id_stack = new TIdStackWindows;
  if (id_stack) {
    host_ip = id_stack->LocalAddress;
    delete id_stack;
  }
}

官方推荐优化版本

根据Indy维护者Remy的建议,不建议手动实例化TIdStack子类,应使用全局GStack实例的标准操作方式:

__fastcall TstartForm::TstartForm(TComponent* Owner) : TForm(Owner)
{
  _progressForm = 0;
  String host_ip = L"";
  TIdStack::IncUsage();
  host_ip = GStack->LocalAddress;
  TIdStack::DecUsage();
  sm->_this_computer_id = host_ip;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 08:45:03