- 本章主要讲如何实现一个网络时间协议NTP(Network Time Protocol)客户端,谷歌的世界时间同步误差大概在7毫秒,开源网站CockroachDB的延迟在数十毫秒,使用了NTP协议,在处理与时间敏感的数据时,
chrono
库成为了事实上的标准库; - 由于潮汐影响和地球转矩的问题,事实上每一秒的长度不是固定的,引出了两种时间机制,一种是TAI,用于世界的原子时钟,每秒长度固定;另一种是UTC,用于通常生活中,差不多每隔18个月会添加1个闰秒,到2016年,TAI和UTC的偏差已经达到了36秒;在计算机系统中通常跑着两种时钟(clocks),一种叫实时时钟(real-time clock),根据物理设备(例如石英钟)的震动来统计时间,用于没有电源驱动的场景,一种叫系统时间(system time),系统时间根据硬件中断来增加,所有电脑上的应用获取时间都是通过system time;
- 9.3节介绍了几个时间有关的术语,例如
Absolute time
、Real-time clock
、system clock
、monotonically increasing
、steady clock
、High accuracy
、High resolution
、fast clock
等等,对于理解各种不同的时间有很大的帮助; - 时间的编码使用了2个32位integer,第一个表示秒,第二个表示n分之一秒(fraction of a second),好处有两点,简单易懂,计算高效;挑战也有两点,范围固定(有上限,因为integer宽度有限),不准确(整型是离散的而不是连续的),几个常见的表示时间的方式有,a. UNIX时间戳,32位整型,表示从1970年1月1日其的毫秒数;b. MS Windows FILETIME(从Windows 2000开始启用),64位无符号整型,表示从1601年1月1日(UTC时间)到当时的100纳秒的增量(increments);c. Rust社区的chrono库,32位有符号整型,同时带有NaiveTime的枚举类型来表示不同的时区;d. time_t类型,在C标准库libc里,不同版本也有一定区别,详见Page298;
- 9.5给出了应用获得系统时间的具体调用过程,如下
- 获取本地时间的方法可以使用
chrono::Local::now()
,如果返回值是感叹号!
,表示该函数永不返回,代码跑到unimplemented!()
宏这里时会panic; - 用
clap::Arg
或者clap::App
来处理输入参数,clap::Arg
可以帮助简单处理输入参数,clap::App
把整个程序封装成应用,可以添加版本、参数说明、参数是否必须等要求; - 可以在
cargo.toml
指定[target.'cfg(not(windows))'.dependencies]
用于非windows操作系统编译时的依赖,同理,去掉not可以用于设置Windows操作系统的依赖; - NTP有两种模式,一种是always on,采用p2p的形式来在局域网中达成一个稳定的关于"now"的共识,一种是request/response,通过向服务器发送请求(request)来获取一个中心化认可的时间戳,通过记录传输时间来校准;
- request/response模式有4个时间点需要记录,t1表示客户端发出request的时间戳、t2表示服务端收到客户端request的时间戳、t3表示服务端发出response的时间戳、t4表示客户端收到response的时间戳,这4个时间戳的格式在RFC2030中规定,流程如下图所示,9.9.1节提供了详细实现11. NTP中要计算两个值, θ \theta θ 和 δ \delta δ,如下表所示,表示从客户端到服务端的传输延迟,实际应用中会发送requests到多个server来减小单个服务的误差