github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/dial.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 //版权所有2015 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 package p2p 26 27 import ( 28 "container/heap" 29 "crypto/rand" 30 "errors" 31 "fmt" 32 "net" 33 "time" 34 35 "github.com/ethereum/go-ethereum/log" 36 "github.com/ethereum/go-ethereum/p2p/discover" 37 "github.com/ethereum/go-ethereum/p2p/netutil" 38 ) 39 40 const ( 41 //这是介于 42 //重拨某个节点。 43 dialHistoryExpiration = 30 * time.Second 44 45 //发现查找受到限制,只能运行 46 //每隔几秒钟一次。 47 lookupInterval = 4 * time.Second 48 49 //如果在这段时间内找不到对等点,则初始引导节点为 50 //试图连接。 51 fallbackInterval = 20 * time.Second 52 53 //端点分辨率通过有界退避进行限制。 54 initialResolveDelay = 60 * time.Second 55 maxResolveDelay = time.Hour 56 ) 57 58 //nodeadialer用于连接到网络中的节点,通常使用 59 //一个底层的net.dialer,但在测试中也使用了net.pipe 60 type NodeDialer interface { 61 Dial(*discover.Node) (net.Conn, error) 62 } 63 64 //tcpDialer通过使用net.dialer 65 //创建到网络中节点的TCP连接 66 type TCPDialer struct { 67 *net.Dialer 68 } 69 70 //拨号创建到节点的TCP连接 71 func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) { 72 addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)} 73 return t.Dialer.Dial("tcp", addr.String()) 74 } 75 76 //拨号状态计划拨号和查找。 77 //每次迭代都有机会计算新任务 78 //在server.run中的主循环。 79 type dialstate struct { 80 maxDynDials int 81 ntab discoverTable 82 netrestrict *netutil.Netlist 83 84 lookupRunning bool 85 dialing map[discover.NodeID]connFlag 86 lookupBuf []*discover.Node //当前发现查找结果 87 randomNodes []*discover.Node //从表中填充 88 static map[discover.NodeID]*dialTask 89 hist *dialHistory 90 91 start time.Time //拨号器首次使用的时间 92 bootnodes []*discover.Node //没有对等机时的默认拨号 93 } 94 95 type discoverTable interface { 96 Self() *discover.Node 97 Close() 98 Resolve(target discover.NodeID) *discover.Node 99 Lookup(target discover.NodeID) []*discover.Node 100 ReadRandomNodes([]*discover.Node) int 101 } 102 103 //拨号历史记录会记住最近的拨号。 104 type dialHistory []pastDial 105 106 //PastDial是拨号历史记录中的一个条目。 107 type pastDial struct { 108 id discover.NodeID 109 exp time.Time 110 } 111 112 type task interface { 113 Do(*Server) 114 } 115 116 //为所拨的每个节点生成一个拨号任务。它的 117 //任务运行时无法访问字段。 118 type dialTask struct { 119 flags connFlag 120 dest *discover.Node 121 lastResolved time.Time 122 resolveDelay time.Duration 123 } 124 125 //discovertask运行发现表操作。 126 //任何时候只有一个discovertask处于活动状态。 127 //discovertask.do执行随机查找。 128 type discoverTask struct { 129 results []*discover.Node 130 } 131 132 //如果没有其他任务,则生成waitexpiretask 133 //在server.run中保持循环。 134 type waitExpireTask struct { 135 time.Duration 136 } 137 138 func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist) *dialstate { 139 s := &dialstate{ 140 maxDynDials: maxdyn, 141 ntab: ntab, 142 netrestrict: netrestrict, 143 static: make(map[discover.NodeID]*dialTask), 144 dialing: make(map[discover.NodeID]connFlag), 145 bootnodes: make([]*discover.Node, len(bootnodes)), 146 randomNodes: make([]*discover.Node, maxdyn/2), 147 hist: new(dialHistory), 148 } 149 copy(s.bootnodes, bootnodes) 150 for _, n := range static { 151 s.addStatic(n) 152 } 153 return s 154 } 155 156 func (s *dialstate) addStatic(n *discover.Node) { 157 //这将覆盖任务,而不是更新现有的 158 //输入,让用户有机会强制执行解决操作。 159 s.static[n.ID] = &dialTask{flags: staticDialedConn, dest: n} 160 } 161 162 func (s *dialstate) removeStatic(n *discover.Node) { 163 //这将删除一个任务,因此将来不会尝试连接。 164 delete(s.static, n.ID) 165 //这将删除以前的拨号时间戳,以便应用程序 166 //可以强制服务器立即与所选对等机重新连接。 167 s.hist.remove(n.ID) 168 } 169 170 func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task { 171 if s.start.IsZero() { 172 s.start = now 173 } 174 175 var newtasks []task 176 addDial := func(flag connFlag, n *discover.Node) bool { 177 if err := s.checkDial(n, peers); err != nil { 178 log.Trace("Skipping dial candidate", "id", n.ID, "addr", &net.TCPAddr{IP: n.IP, Port: int(n.TCP)}, "err", err) 179 return false 180 } 181 s.dialing[n.ID] = flag 182 newtasks = append(newtasks, &dialTask{flags: flag, dest: n}) 183 return true 184 } 185 186 //计算此时所需的动态拨号数。 187 needDynDials := s.maxDynDials 188 for _, p := range peers { 189 if p.rw.is(dynDialedConn) { 190 needDynDials-- 191 } 192 } 193 for _, flag := range s.dialing { 194 if flag&dynDialedConn != 0 { 195 needDynDials-- 196 } 197 } 198 199 //每次调用时使拨号历史记录过期。 200 s.hist.expire(now) 201 202 //如果静态节点未连接,则为其创建拨号。 203 for id, t := range s.static { 204 err := s.checkDial(t.dest, peers) 205 switch err { 206 case errNotWhitelisted, errSelf: 207 log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "err", err) 208 delete(s.static, t.dest.ID) 209 case nil: 210 s.dialing[id] = t.flags 211 newtasks = append(newtasks, t) 212 } 213 } 214 //如果我们没有任何对等点,请尝试拨打随机引导节点。这个 215 //场景对于发现 216 //桌子上可能满是坏同学,很难找到好同学。 217 if len(peers) == 0 && len(s.bootnodes) > 0 && needDynDials > 0 && now.Sub(s.start) > fallbackInterval { 218 bootnode := s.bootnodes[0] 219 s.bootnodes = append(s.bootnodes[:0], s.bootnodes[1:]...) 220 s.bootnodes = append(s.bootnodes, bootnode) 221 222 if addDial(dynDialedConn, bootnode) { 223 needDynDials-- 224 } 225 } 226 //将表中的随机节点用于所需的一半 227 //动态拨号。 228 randomCandidates := needDynDials / 2 229 if randomCandidates > 0 { 230 n := s.ntab.ReadRandomNodes(s.randomNodes) 231 for i := 0; i < randomCandidates && i < n; i++ { 232 if addDial(dynDialedConn, s.randomNodes[i]) { 233 needDynDials-- 234 } 235 } 236 } 237 //从随机查找结果创建动态拨号,已尝试删除 238 //结果缓冲区中的项。 239 i := 0 240 for ; i < len(s.lookupBuf) && needDynDials > 0; i++ { 241 if addDial(dynDialedConn, s.lookupBuf[i]) { 242 needDynDials-- 243 } 244 } 245 s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])] 246 //如果需要更多候选项,则启动查找。 247 if len(s.lookupBuf) < needDynDials && !s.lookupRunning { 248 s.lookupRunning = true 249 newtasks = append(newtasks, &discoverTask{}) 250 } 251 252 //启动计时器,等待下一个节点全部过期 253 //候选人已被试用,目前没有活动任务。 254 //这样可以防止拨号程序逻辑没有勾选的情况发生。 255 //因为没有挂起的事件。 256 if nRunning == 0 && len(newtasks) == 0 && s.hist.Len() > 0 { 257 t := &waitExpireTask{s.hist.min().exp.Sub(now)} 258 newtasks = append(newtasks, t) 259 } 260 return newtasks 261 } 262 263 var ( 264 errSelf = errors.New("is self") 265 errAlreadyDialing = errors.New("already dialing") 266 errAlreadyConnected = errors.New("already connected") 267 errRecentlyDialed = errors.New("recently dialed") 268 errNotWhitelisted = errors.New("not contained in netrestrict whitelist") 269 ) 270 271 func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) error { 272 _, dialing := s.dialing[n.ID] 273 switch { 274 case dialing: 275 return errAlreadyDialing 276 case peers[n.ID] != nil: 277 return errAlreadyConnected 278 case s.ntab != nil && n.ID == s.ntab.Self().ID: 279 return errSelf 280 case s.netrestrict != nil && !s.netrestrict.Contains(n.IP): 281 return errNotWhitelisted 282 case s.hist.contains(n.ID): 283 return errRecentlyDialed 284 } 285 return nil 286 } 287 288 func (s *dialstate) taskDone(t task, now time.Time) { 289 switch t := t.(type) { 290 case *dialTask: 291 s.hist.add(t.dest.ID, now.Add(dialHistoryExpiration)) 292 delete(s.dialing, t.dest.ID) 293 case *discoverTask: 294 s.lookupRunning = false 295 s.lookupBuf = append(s.lookupBuf, t.results...) 296 } 297 } 298 299 func (t *dialTask) Do(srv *Server) { 300 if t.dest.Incomplete() { 301 if !t.resolve(srv) { 302 return 303 } 304 } 305 err := t.dial(srv, t.dest) 306 if err != nil { 307 log.Trace("Dial error", "task", t, "err", err) 308 //如果拨号失败,请尝试解析静态节点的ID。 309 if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 { 310 if t.resolve(srv) { 311 t.dial(srv, t.dest) 312 } 313 } 314 } 315 } 316 317 //解决查找目标的当前终结点的尝试 318 //使用发现。 319 // 320 //解决操作通过后退进行节流,以避免淹没 321 //对不存在的节点进行无用查询的发现网络。 322 //当找到节点时,退避延迟重置。 323 func (t *dialTask) resolve(srv *Server) bool { 324 if srv.ntab == nil { 325 log.Debug("Can't resolve node", "id", t.dest.ID, "err", "discovery is disabled") 326 return false 327 } 328 if t.resolveDelay == 0 { 329 t.resolveDelay = initialResolveDelay 330 } 331 if time.Since(t.lastResolved) < t.resolveDelay { 332 return false 333 } 334 resolved := srv.ntab.Resolve(t.dest.ID) 335 t.lastResolved = time.Now() 336 if resolved == nil { 337 t.resolveDelay *= 2 338 if t.resolveDelay > maxResolveDelay { 339 t.resolveDelay = maxResolveDelay 340 } 341 log.Debug("Resolving node failed", "id", t.dest.ID, "newdelay", t.resolveDelay) 342 return false 343 } 344 //找到节点。 345 t.resolveDelay = initialResolveDelay 346 t.dest = resolved 347 log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}) 348 return true 349 } 350 351 type dialError struct { 352 error 353 } 354 355 //拨号执行实际连接尝试。 356 func (t *dialTask) dial(srv *Server, dest *discover.Node) error { 357 fd, err := srv.Dialer.Dial(dest) 358 if err != nil { 359 return &dialError{err} 360 } 361 mfd := newMeteredConn(fd, false) 362 return srv.SetupConn(mfd, t.flags, dest) 363 } 364 365 func (t *dialTask) String() string { 366 return fmt.Sprintf("%v %x %v:%d", t.flags, t.dest.ID[:8], t.dest.IP, t.dest.TCP) 367 } 368 369 func (t *discoverTask) Do(srv *Server) { 370 //每当动态拨号 371 //必要的。查找需要花费一些时间,否则 372 //事件循环旋转过快。 373 next := srv.lastLookup.Add(lookupInterval) 374 if now := time.Now(); now.Before(next) { 375 time.Sleep(next.Sub(now)) 376 } 377 srv.lastLookup = time.Now() 378 var target discover.NodeID 379 rand.Read(target[:]) 380 t.results = srv.ntab.Lookup(target) 381 } 382 383 func (t *discoverTask) String() string { 384 s := "discovery lookup" 385 if len(t.results) > 0 { 386 s += fmt.Sprintf(" (%d results)", len(t.results)) 387 } 388 return s 389 } 390 391 func (t waitExpireTask) Do(*Server) { 392 time.Sleep(t.Duration) 393 } 394 func (t waitExpireTask) String() string { 395 return fmt.Sprintf("wait for dial hist expire (%v)", t.Duration) 396 } 397 398 //仅使用这些方法访问或修改拨号历史记录。 399 func (h dialHistory) min() pastDial { 400 return h[0] 401 } 402 func (h *dialHistory) add(id discover.NodeID, exp time.Time) { 403 heap.Push(h, pastDial{id, exp}) 404 405 } 406 func (h *dialHistory) remove(id discover.NodeID) bool { 407 for i, v := range *h { 408 if v.id == id { 409 heap.Remove(h, i) 410 return true 411 } 412 } 413 return false 414 } 415 func (h dialHistory) contains(id discover.NodeID) bool { 416 for _, v := range h { 417 if v.id == id { 418 return true 419 } 420 } 421 return false 422 } 423 func (h *dialHistory) expire(now time.Time) { 424 for h.Len() > 0 && h.min().exp.Before(now) { 425 heap.Pop(h) 426 } 427 } 428 429 //堆接口样板 430 func (h dialHistory) Len() int { return len(h) } 431 func (h dialHistory) Less(i, j int) bool { return h[i].exp.Before(h[j].exp) } 432 func (h dialHistory) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 433 func (h *dialHistory) Push(x interface{}) { 434 *h = append(*h, x.(pastDial)) 435 } 436 func (h *dialHistory) Pop() interface{} { 437 old := *h 438 n := len(old) 439 x := old[n-1] 440 *h = old[0 : n-1] 441 return x 442 }