github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/discover/ntp.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2016 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  //包含通过sntp协议进行的ntp时间漂移检测:
    26  //https://tools.ietf.org/html/rfc4330
    27  
    28  package discover
    29  
    30  import (
    31  	"fmt"
    32  	"net"
    33  	"sort"
    34  	"time"
    35  
    36  	"github.com/ethereum/go-ethereum/log"
    37  )
    38  
    39  const (
    40  ntpPool   = "pool.ntp.org" //ntppool是要查询当前时间的ntp服务器
    41  ntpChecks = 3              //要对NTP服务器执行的测量数
    42  )
    43  
    44  //DurationSicle将Sort.Interface方法附加到[]Time.Duration,
    45  //按递增顺序排序。
    46  type durationSlice []time.Duration
    47  
    48  func (s durationSlice) Len() int           { return len(s) }
    49  func (s durationSlice) Less(i, j int) bool { return s[i] < s[j] }
    50  func (s durationSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    51  
    52  //checkclockfloft查询NTP服务器的时钟偏移,并警告用户
    53  //检测到一个足够大的。
    54  func checkClockDrift() {
    55  	drift, err := sntpDrift(ntpChecks)
    56  	if err != nil {
    57  		return
    58  	}
    59  	if drift < -driftThreshold || drift > driftThreshold {
    60  		log.Warn(fmt.Sprintf("System clock seems off by %v, which can prevent network connectivity", drift))
    61  		log.Warn("Please enable network time synchronisation in system settings.")
    62  	} else {
    63  		log.Debug("NTP sanity check done", "drift", drift)
    64  	}
    65  }
    66  
    67  //sntpdrift针对ntp服务器执行幼稚的时间解析,并返回
    68  //测量漂移。此方法使用简单版本的NTP。不太准确
    69  //但就这些目的而言应该是好的。
    70  //
    71  //注意,与请求的数量相比,它执行两个额外的测量
    72  //一种能够将这两个极端作为离群值丢弃的方法。
    73  func sntpDrift(measurements int) (time.Duration, error) {
    74  //解析NTP服务器的地址
    75  	addr, err := net.ResolveUDPAddr("udp", ntpPool+":123")
    76  	if err != nil {
    77  		return 0, err
    78  	}
    79  //构造时间请求(仅设置两个字段的空包):
    80  //位3-5:协议版本,3
    81  //位6-8:操作模式,客户机,3
    82  	request := make([]byte, 48)
    83  	request[0] = 3<<3 | 3
    84  
    85  //执行每个测量
    86  	drifts := []time.Duration{}
    87  	for i := 0; i < measurements+2; i++ {
    88  //拨号NTP服务器并发送时间检索请求
    89  		conn, err := net.DialUDP("udp", nil, addr)
    90  		if err != nil {
    91  			return 0, err
    92  		}
    93  		defer conn.Close()
    94  
    95  		sent := time.Now()
    96  		if _, err = conn.Write(request); err != nil {
    97  			return 0, err
    98  		}
    99  //检索回复并计算经过的时间
   100  		conn.SetDeadline(time.Now().Add(5 * time.Second))
   101  
   102  		reply := make([]byte, 48)
   103  		if _, err = conn.Read(reply); err != nil {
   104  			return 0, err
   105  		}
   106  		elapsed := time.Since(sent)
   107  
   108  //从回复数据中重建时间
   109  		sec := uint64(reply[43]) | uint64(reply[42])<<8 | uint64(reply[41])<<16 | uint64(reply[40])<<24
   110  		frac := uint64(reply[47]) | uint64(reply[46])<<8 | uint64(reply[45])<<16 | uint64(reply[44])<<24
   111  
   112  		nanosec := sec*1e9 + (frac*1e9)>>32
   113  
   114  		t := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nanosec)).Local()
   115  
   116  //根据假定的响应时间rrt/2计算漂移
   117  		drifts = append(drifts, sent.Sub(t)+elapsed/2)
   118  	}
   119  //计算平均干重(减少两端以避免异常值)
   120  	sort.Sort(durationSlice(drifts))
   121  
   122  	drift := time.Duration(0)
   123  	for i := 1; i < len(drifts)-1; i++ {
   124  		drift += drifts[i]
   125  	}
   126  	return drift / time.Duration(measurements), nil
   127  }