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

如何重置Indy UDP客户端缓冲区?解决TIdSNTP旧数据干扰问题

Indy TIdSNTP组件旧数据报残留问题的解决方法

我发现Indy的TIdSNTP组件存在一个小问题:当超时时间小于实际网络延迟时,发起DateTime请求后,数据报无法在超时时间内接收;但该旧数据报会被保存在某个内部缓冲区中,下次调用DateTime时会接收到这个旧数据报,从而返回错误的时间值。

示例代码:

var sntp1: TIdSNTP := TIdSNTP.Create;
sntp1.Host := 'pool.ntp.org';
sntp1.ReceiveTimeout := 5;
sntp1.DateTime;
Memo1.Lines.Add(Format(' delay: %d', [ round(sntp1.RoundTripDelay * MSecsPerDay) ]));
Application.ProcessMessages;
sleep(3000);
sntp1.ReceiveTimeout := 500;
sntp1.DateTime;
Memo1.Lines.Add(Format(' delay: %d', [ round(sntp1.RoundTripDelay * MSecsPerDay) ]));

问题:在下次调用DateTime之前,如何正确重置缓冲区以清除旧的待处理数据?


可以通过以下几种方式解决:

  • 主动清空底层套接字缓冲区:直接操作组件的底层绑定套接字,读取所有残留数据清空缓冲区。示例代码:

    var
      Buffer: array[0..1023] of Byte;
      BytesRead: Integer;
    begin
      if Assigned(sntp1.Binding) then
      begin
        // 设置非阻塞模式快速读取残留数据
        sntp1.Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVTIMEO, 0);
        repeat
          BytesRead := sntp1.Binding.Receive(Buffer, SizeOf(Buffer), 0);
        until BytesRead <= 0;
        // 恢复原接收超时设置
        sntp1.Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVTIMEO, sntp1.ReceiveTimeout);
      end;
    end;
    
  • 调用Disconnect方法重置套接字:TIdSNTP继承自TIdUDPBase,调用Disconnect会关闭并重新创建底层套接字,彻底清空缓冲区。下次调用DateTime时组件会自动重新连接,不影响正常使用:

    sntp1.Disconnect;
    
  • 重新创建组件实例:如果场景允许,直接销毁原实例并重新创建,彻底清除所有内部状态和缓冲区数据:

    sntp1.Free;
    sntp1 := TIdSNTP.Create;
    sntp1.Host := 'pool.ntp.org';
    sntp1.ReceiveTimeout := 500;
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 16:09:59