如何重置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
相关产品推荐
相关产品推荐

