github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/peer.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 //版权所有2014 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 "errors" 29 "fmt" 30 "io" 31 "net" 32 "sort" 33 "sync" 34 "time" 35 36 "github.com/ethereum/go-ethereum/common/mclock" 37 "github.com/ethereum/go-ethereum/event" 38 "github.com/ethereum/go-ethereum/log" 39 "github.com/ethereum/go-ethereum/p2p/discover" 40 "github.com/ethereum/go-ethereum/rlp" 41 ) 42 43 var ( 44 ErrShuttingDown = errors.New("shutting down") 45 ) 46 47 const ( 48 baseProtocolVersion = 5 49 baseProtocolLength = uint64(16) 50 baseProtocolMaxMsgSize = 2 * 1024 51 52 snappyProtocolVersion = 5 53 54 pingInterval = 15 * time.Second 55 ) 56 57 const ( 58 //DEVP2P消息代码 59 handshakeMsg = 0x00 60 discMsg = 0x01 61 pingMsg = 0x02 62 pongMsg = 0x03 63 ) 64 65 //协议握手是协议握手的RLP结构。 66 type protoHandshake struct { 67 Version uint64 68 Name string 69 Caps []Cap 70 ListenPort uint64 71 ID discover.NodeID 72 73 //忽略其他字段(为了向前兼容)。 74 Rest []rlp.RawValue `rlp:"tail"` 75 } 76 77 //PeerEventType是P2P服务器发出的对等事件类型。 78 type PeerEventType string 79 80 const ( 81 //PeerEventTypeAdd是添加对等方时发出的事件类型 82 //到P2P服务器 83 PeerEventTypeAdd PeerEventType = "add" 84 85 //PeerEventTypeDrop是当对等机 86 //从p2p服务器上删除 87 PeerEventTypeDrop PeerEventType = "drop" 88 89 //PeerEventTypeMSGSEND是在 90 //消息已成功发送到对等方 91 PeerEventTypeMsgSend PeerEventType = "msgsend" 92 93 //PeerEventTypeMsgrecv是在 94 //从对等端接收消息 95 PeerEventTypeMsgRecv PeerEventType = "msgrecv" 96 ) 97 98 //PeerEvent是在添加或删除对等方时发出的事件 99 //一个p2p服务器,或者当通过对等连接发送或接收消息时 100 type PeerEvent struct { 101 Type PeerEventType `json:"type"` 102 Peer discover.NodeID `json:"peer"` 103 Error string `json:"error,omitempty"` 104 Protocol string `json:"protocol,omitempty"` 105 MsgCode *uint64 `json:"msg_code,omitempty"` 106 MsgSize *uint32 `json:"msg_size,omitempty"` 107 } 108 109 //对等表示已连接的远程节点。 110 type Peer struct { 111 rw *conn 112 running map[string]*protoRW 113 log log.Logger 114 created mclock.AbsTime 115 116 wg sync.WaitGroup 117 protoErr chan error 118 closed chan struct{} 119 disc chan DiscReason 120 121 //事件接收消息发送/接收事件(如果设置) 122 events *event.Feed 123 } 124 125 //newpeer返回用于测试目的的对等机。 126 func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer { 127 pipe, _ := net.Pipe() 128 conn := &conn{fd: pipe, transport: nil, id: id, caps: caps, name: name} 129 peer := newPeer(conn, nil) 130 close(peer.closed) //确保断开连接不会阻塞 131 return peer 132 } 133 134 //ID返回节点的公钥。 135 func (p *Peer) ID() discover.NodeID { 136 return p.rw.id 137 } 138 139 //name返回远程节点公布的节点名。 140 func (p *Peer) Name() string { 141 return p.rw.name 142 } 143 144 //caps返回远程对等机的功能(支持的子协议)。 145 func (p *Peer) Caps() []Cap { 146 //托多:也许还回副本 147 return p.rw.caps 148 } 149 150 //remoteaddr返回网络连接的远程地址。 151 func (p *Peer) RemoteAddr() net.Addr { 152 return p.rw.fd.RemoteAddr() 153 } 154 155 //localaddr返回网络连接的本地地址。 156 func (p *Peer) LocalAddr() net.Addr { 157 return p.rw.fd.LocalAddr() 158 } 159 160 //disconnect以给定的原因终止对等连接。 161 //它会立即返回,并且不会等待连接关闭。 162 func (p *Peer) Disconnect(reason DiscReason) { 163 select { 164 case p.disc <- reason: 165 case <-p.closed: 166 } 167 } 168 169 //字符串实现fmt.stringer。 170 func (p *Peer) String() string { 171 return fmt.Sprintf("Peer %x %v", p.rw.id[:8], p.RemoteAddr()) 172 } 173 174 //如果对等端是入站连接,则inbound返回true 175 func (p *Peer) Inbound() bool { 176 return p.rw.is(inboundConn) 177 } 178 179 func newPeer(conn *conn, protocols []Protocol) *Peer { 180 protomap := matchProtocols(protocols, conn.caps, conn) 181 p := &Peer{ 182 rw: conn, 183 running: protomap, 184 created: mclock.Now(), 185 disc: make(chan DiscReason), 186 protoErr: make(chan error, len(protomap)+1), //协议+PingLoop 187 closed: make(chan struct{}), 188 log: log.New("id", conn.id, "conn", conn.flags), 189 } 190 return p 191 } 192 193 func (p *Peer) Log() log.Logger { 194 return p.log 195 } 196 197 func (p *Peer) run() (remoteRequested bool, err error) { 198 var ( 199 writeStart = make(chan struct{}, 1) 200 writeErr = make(chan error, 1) 201 readErr = make(chan error, 1) 202 reason DiscReason //发送给对等方 203 ) 204 p.wg.Add(2) 205 go p.readLoop(readErr) 206 go p.pingLoop() 207 208 //启动所有协议处理程序。 209 writeStart <- struct{}{} 210 p.startProtocols(writeStart, writeErr) 211 212 //等待错误或断开连接。 213 loop: 214 for { 215 select { 216 case err = <-writeErr: 217 //已完成写入。允许在以下情况下开始下一次写入 218 //没有错误。 219 if err != nil { 220 reason = DiscNetworkError 221 break loop 222 } 223 writeStart <- struct{}{} 224 case err = <-readErr: 225 if r, ok := err.(DiscReason); ok { 226 remoteRequested = true 227 reason = r 228 } else { 229 reason = DiscNetworkError 230 } 231 break loop 232 case err = <-p.protoErr: 233 reason = discReasonForError(err) 234 break loop 235 case err = <-p.disc: 236 reason = discReasonForError(err) 237 break loop 238 } 239 } 240 241 close(p.closed) 242 p.rw.close(reason) 243 p.wg.Wait() 244 return remoteRequested, err 245 } 246 247 func (p *Peer) pingLoop() { 248 ping := time.NewTimer(pingInterval) 249 defer p.wg.Done() 250 defer ping.Stop() 251 for { 252 select { 253 case <-ping.C: 254 if err := SendItems(p.rw, pingMsg); err != nil { 255 p.protoErr <- err 256 return 257 } 258 ping.Reset(pingInterval) 259 case <-p.closed: 260 return 261 } 262 } 263 } 264 265 func (p *Peer) readLoop(errc chan<- error) { 266 defer p.wg.Done() 267 for { 268 msg, err := p.rw.ReadMsg() 269 if err != nil { 270 errc <- err 271 return 272 } 273 msg.ReceivedAt = time.Now() 274 if err = p.handle(msg); err != nil { 275 errc <- err 276 return 277 } 278 } 279 } 280 281 func (p *Peer) handle(msg Msg) error { 282 switch { 283 case msg.Code == pingMsg: 284 msg.Discard() 285 go SendItems(p.rw, pongMsg) 286 case msg.Code == discMsg: 287 var reason [1]DiscReason 288 //这是最后一条信息。我们不需要抛弃或 289 //检查错误,因为连接之后将关闭。 290 rlp.Decode(msg.Payload, &reason) 291 return reason[0] 292 case msg.Code < baseProtocolLength: 293 //忽略其他基本协议消息 294 return msg.Discard() 295 default: 296 //这是一个子协议消息 297 proto, err := p.getProto(msg.Code) 298 if err != nil { 299 return fmt.Errorf("msg code out of range: %v", msg.Code) 300 } 301 select { 302 case proto.in <- msg: 303 return nil 304 case <-p.closed: 305 return io.EOF 306 } 307 } 308 return nil 309 } 310 311 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 312 n := 0 313 for _, cap := range caps { 314 for _, proto := range protocols { 315 if proto.Name == cap.Name && proto.Version == cap.Version { 316 n++ 317 } 318 } 319 } 320 return n 321 } 322 323 //MatchProtocols为匹配命名的子协议创建结构。 324 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 325 sort.Sort(capsByNameAndVersion(caps)) 326 offset := baseProtocolLength 327 result := make(map[string]*protoRW) 328 329 outer: 330 for _, cap := range caps { 331 for _, proto := range protocols { 332 if proto.Name == cap.Name && proto.Version == cap.Version { 333 //如果旧协议版本匹配,请将其还原 334 if old := result[cap.Name]; old != nil { 335 offset -= old.Length 336 } 337 //分配新匹配项 338 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 339 offset += proto.Length 340 341 continue outer 342 } 343 } 344 } 345 return result 346 } 347 348 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 349 p.wg.Add(len(p.running)) 350 for _, proto := range p.running { 351 proto := proto 352 proto.closed = p.closed 353 proto.wstart = writeStart 354 proto.werr = writeErr 355 var rw MsgReadWriter = proto 356 if p.events != nil { 357 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 358 } 359 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 360 go func() { 361 err := proto.Run(p, rw) 362 if err == nil { 363 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 364 err = errProtocolReturned 365 } else if err != io.EOF { 366 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 367 } 368 p.protoErr <- err 369 p.wg.Done() 370 }() 371 } 372 } 373 374 //getproto查找负责处理的协议 375 //给定的消息代码。 376 func (p *Peer) getProto(code uint64) (*protoRW, error) { 377 for _, proto := range p.running { 378 if code >= proto.offset && code < proto.offset+proto.Length { 379 return proto, nil 380 } 381 } 382 return nil, newPeerError(errInvalidMsgCode, "%d", code) 383 } 384 385 type protoRW struct { 386 Protocol 387 in chan Msg //接收已读消息 388 closed <-chan struct{} //对等机关闭时接收 389 wstart <-chan struct{} //当写入可能开始时接收 390 werr chan<- error //用于写入结果 391 offset uint64 392 w MsgWriter 393 } 394 395 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 396 if msg.Code >= rw.Length { 397 return newPeerError(errInvalidMsgCode, "not handled") 398 } 399 msg.Code += rw.offset 400 select { 401 case <-rw.wstart: 402 err = rw.w.WriteMsg(msg) 403 //将写状态报告回peer.run。它将启动 404 //如果错误为非零,则关闭并取消阻止下一次写入 405 //否则。如果出现错误,调用协议代码应退出。 406 //但我们不想依赖它。 407 rw.werr <- err 408 case <-rw.closed: 409 err = ErrShuttingDown 410 } 411 return err 412 } 413 414 func (rw *protoRW) ReadMsg() (Msg, error) { 415 select { 416 case msg := <-rw.in: 417 msg.Code -= rw.offset 418 return msg, nil 419 case <-rw.closed: 420 return Msg{}, io.EOF 421 } 422 } 423 424 //PeerInfo表示有关连接的 425 //同龄人。子协议独立字段包含在此处并在此处初始化,使用 426 //协议细节委托给所有连接的子协议。 427 type PeerInfo struct { 428 ID string `json:"id"` //唯一节点标识符(也是加密密钥) 429 Name string `json:"name"` //节点的名称,包括客户端类型、版本、操作系统、自定义数据 430 Caps []string `json:"caps"` //此特定对等方公布的SUM协议 431 Network struct { 432 LocalAddress string `json:"localAddress"` //TCP数据连接的本地终结点 433 RemoteAddress string `json:"remoteAddress"` //TCP数据连接的远程终结点 434 Inbound bool `json:"inbound"` 435 Trusted bool `json:"trusted"` 436 Static bool `json:"static"` 437 } `json:"network"` 438 Protocols map[string]interface{} `json:"protocols"` //子协议特定的元数据字段 439 } 440 441 //INFO收集并返回有关对等机的已知元数据集合。 442 func (p *Peer) Info() *PeerInfo { 443 //收集协议功能 444 var caps []string 445 for _, cap := range p.Caps() { 446 caps = append(caps, cap.String()) 447 } 448 //组装通用对等元数据 449 info := &PeerInfo{ 450 ID: p.ID().String(), 451 Name: p.Name(), 452 Caps: caps, 453 Protocols: make(map[string]interface{}), 454 } 455 info.Network.LocalAddress = p.LocalAddr().String() 456 info.Network.RemoteAddress = p.RemoteAddr().String() 457 info.Network.Inbound = p.rw.is(inboundConn) 458 info.Network.Trusted = p.rw.is(trustedConn) 459 info.Network.Static = p.rw.is(staticDialedConn) 460 461 //收集所有正在运行的协议信息 462 for _, proto := range p.running { 463 protoInfo := interface{}("unknown") 464 if query := proto.Protocol.PeerInfo; query != nil { 465 if metadata := query(p.ID()); metadata != nil { 466 protoInfo = metadata 467 } else { 468 protoInfo = "handshake" 469 } 470 } 471 info.Protocols[proto.Name] = protoInfo 472 } 473 return info 474 }