比特币全节点Go语言实现BTCD之网络连接过程


启动server:

// Start begins accepting connections from peers.
func (s *server) Start() {
   ....
   go s.peerHandler()

   if !cfg.DisableRPC {
      s.wg.Add(1)

      go s.rebroadcastHandler()

      s.rpcServer.Start()
   }

   // Start the CPU miner if generation is enabled.
   if cfg.Generate {
      s.cpuMiner.Start()
   }
}

peerHandler负责启动节点的地址管理、同步管理、连接管理等,主要代码逻辑:

func (s *server) peerHandler() {

   s.addrManager.Start()
   s.syncManager.Start()

   srvrLog.Tracef("Starting peer handler")

   state := &peerState{
      inboundPeers:    make(map[int32]*serverPeer),
      persistentPeers: make(map[int32]*serverPeer),
      outboundPeers:   make(map[int32]*serverPeer),
      banned:          make(map[string]time.Time),
      outboundGroups:  make(map[string]int),
   }

   if !cfg.DisableDNSSeed {
      connmgr.SeedFromDNS(activeNetParams.Params, defaultRequiredServices, btcdLookup, func(addrs []*wire.NetAddress) {
            s.addrManager.AddAddresses(addrs, addrs[0])
         })
   }
   go s.connManager.Start()

out:
   for {
      select {
      // New peers connected to the server.
      case p := <-s.newPeers:
         s.handleAddPeerMsg(state, p)

      // Disconnected peers.
      case p := <-s.donePeers:
         s.handleDonePeerMsg(state, p)

      // Block accepted in mainchain or orphan, update peer height.
      case umsg := <-s.peerHeightsUpdate:
         s.handleUpdatePeerHeights(state, umsg)

      // Peer to ban.
      case p := <-s.banPeers:
         s.handleBanPeerMsg(state, p)

      // New inventory to potentially be relayed to other peers.
      case invMsg := <-s.relayInv:
         s.handleRelayInvMsg(state, invMsg)

      // Message to broadcast to all connected peers except those
      // which are excluded by the message.
      case bmsg := <-s.broadcast:
         s.handleBroadcastMsg(state, &bmsg)

      case qmsg := <-s.query:
         s.handleQuery(state, qmsg)

      case <-s.quit:
         // Disconnect all peers on server shutdown.
         state.forAllPeers(func(sp *serverPeer) {
            srvrLog.Tracef("Shutdown peer %s", sp)
            sp.Disconnect()
         })
         break out
      }
   }
.............
}

1.先执行节点地址管理

s.addrManager.Start()

主要逻辑:

func (a *AddrManager) Start() {
.......
   a.loadPeers() //从文件加载节点列表
.......
   go a.addressHandler()
}
go a.addressHandler()

定时保存地址列表到peer.json文件

2.启动同步管理

s.syncManager.Start()

主要逻辑是调用blockHandler()方法

func (sm *SyncManager) blockHandler() {
out:
   for {
      select {
      case m := <-sm.msgChan:
         switch msg := m.(type) {
         case *newPeerMsg:
            sm.handleNewPeerMsg(msg.peer)

         case *txMsg:
            sm.handleTxMsg(msg)
            msg.reply <- struct{}{}

         case *blockMsg:
            sm.handleBlockMsg(msg)
            msg.reply <- struct{}{}

         case *invMsg:
            sm.handleInvMsg(msg)

         case *headersMsg:
            sm.handleHeadersMsg(msg)

         case *donePeerMsg:
            sm.handleDonePeerMsg(msg.peer)

         case getSyncPeerMsg:
            var peerID int32
            if sm.syncPeer != nil {
               peerID = sm.syncPeer.ID()
            }
            msg.reply <- peerID

         case processBlockMsg:
            _, isOrphan, err := sm.chain.ProcessBlock(
               msg.block, msg.flags)
            if err != nil {
               msg.reply <- processBlockResponse{
                  isOrphan: false,
                  err:      err,
               }
            }

            msg.reply <- processBlockResponse{
               isOrphan: isOrphan,
               err:      nil,
            }

         case isCurrentMsg:
            msg.reply <- sm.current()

         case pauseMsg:
            // Wait until the sender unpauses the manager.
            <-msg.unpause

         default:
            log.Warnf("Invalid message type in block "+
               "handler: %T", msg)
         }

      case <-sm.quit:
         break out
      }
   }

   sm.wg.Done()
   log.Trace("Block handler done")
}

从通道case m := <-sm.msgChan:处理块消息,然后分发处理。

3.解析dns seed

connmgr.SeedFromDNS(activeNetParams.Params, defaultRequiredServices,
   btcdLookup, func(addrs []*wire.NetAddress) {

通过dns seed获得节点地址,将返回的节点地址添加到addrManager

4.连接管理

go s.connManager.Start()

启动连接管理,主要逻辑:

func (cm *ConnManager) Start() {
   ......
   go cm.connHandler()

   if cm.cfg.OnAccept != nil {
      for _, listner := range cm.cfg.Listeners {
         cm.wg.Add(1)
         go cm.listenHandler(listner)
      }
   }

   for i := atomic.LoadUint64(&cm.connReqCount); i < uint64(cm.cfg.TargetOutbound); i++ {
      go cm.NewConnReq()
   }
}
go cm.connHandler()

从cm.requests通道获得不同类型消息

go cm.listenHandler(listner)
此方法会调用

go cm.cfg.OnAccept(conn)

OnAccept即server的inboundPeerConnected

func (s *server) inboundPeerConnected(conn net.Conn) {
   sp := newServerPeer(s, false)
   sp.isWhitelisted = isWhitelisted(conn.RemoteAddr())
   sp.Peer = peer.NewInboundPeer(newPeerConfig(sp))
   sp.AssociateConnection(conn)
   go s.peerDoneHandler(sp)
}
sp.Peer = peer.NewInboundPeer(newPeerConfig(sp))

对peer进行初始配置,配置如下:

// newPeerConfig returns the configuration for the given serverPeer.
func newPeerConfig(sp *serverPeer) *peer.Config {
   return &peer.Config{
      Listeners: peer.MessageListeners{
         OnVersion:      sp.OnVersion,
         OnMemPool:      sp.OnMemPool,
         OnTx:           sp.OnTx,
         OnBlock:        sp.OnBlock,
         OnInv:          sp.OnInv,
         OnHeaders:      sp.OnHeaders,
         OnGetData:      sp.OnGetData,
         OnGetBlocks:    sp.OnGetBlocks,
         OnGetHeaders:   sp.OnGetHeaders,
         OnGetCFilters:  sp.OnGetCFilters,
         OnGetCFHeaders: sp.OnGetCFHeaders,
         OnGetCFCheckpt: sp.OnGetCFCheckpt,
         OnFeeFilter:    sp.OnFeeFilter,
         OnFilterAdd:    sp.OnFilterAdd,
         OnFilterClear:  sp.OnFilterClear,
         OnFilterLoad:   sp.OnFilterLoad,
         OnGetAddr:      sp.OnGetAddr,
         OnAddr:         sp.OnAddr,
         OnRead:         sp.OnRead,
         OnWrite:        sp.OnWrite,

         // Note: The reference client currently bans peers that send alerts
         // not signed with its key.  We could verify against their key, but
         // since the reference client is currently unwilling to support
         // other implementations' alert messages, we will not relay theirs.
         OnAlert: nil,
      },
      NewestBlock:       sp.newestBlock,
      HostToNetAddress:  sp.server.addrManager.HostToNetAddress,
      Proxy:             cfg.Proxy,
      UserAgentName:     userAgentName,
      UserAgentVersion:  userAgentVersion,
      UserAgentComments: cfg.UserAgentComments,
      ChainParams:       sp.server.chainParams,
      Services:          sp.server.services,
      DisableRelayTx:    cfg.BlocksOnly,
      ProtocolVersion:   peer.MaxProtocolVersion,
   }
}
以上On***会在收到消息时处理。

handleConnected消息会调用

go cm.cfg.OnConnection(connReq, msg.conn)

cm.cfg.OnConnection是在newserver时初始化的,即方法:

func (s *server) outboundPeerConnected(c *connmgr.ConnReq, conn net.Conn) {
   sp := newServerPeer(s, c.Permanent)
   p, err := peer.NewOutboundPeer(newPeerConfig(sp), c.Addr.String())
   if err != nil {
      srvrLog.Debugf("Cannot create outbound peer %s: %v", c.Addr, err)
      s.connManager.Disconnect(c.ID())
   }
   sp.Peer = p
   sp.connReq = c
   sp.isWhitelisted = isWhitelisted(conn.RemoteAddr())
   sp.AssociateConnection(conn)
   go s.peerDoneHandler(sp)
   s.addrManager.Attempt(sp.NA())
}
sp.AssociateConnection(conn)

将sp(ServerPeer)对象与节点关联,并启动节点,主要逻辑:

func (p *Peer) AssociateConnection(conn net.Conn) {
   ....
   p.conn = conn
   p.timeConnected = time.Now()
......
   go func() {
      if err := p.start(); err != nil {
         log.Debugf("Cannot start peer %v: %v", p, err)
         p.Disconnect()
      }
   }()
}

异步启动节点p.start(),

func (p *Peer) start() error {
   log.Tracef("Starting peer %s", p)

   negotiateErr := make(chan error)
   go func() {
      if p.inbound {
         negotiateErr <- p.negotiateInboundProtocol()
      } else {
         negotiateErr <- p.negotiateOutboundProtocol()
      }
   }()

   // Negotiate the protocol within the specified negotiateTimeout.
   select {
   case err := <-negotiateErr:
      if err != nil {
         return err
      }
   case <-time.After(negotiateTimeout):
      return errors.New("protocol negotiation timeout")
   }
   log.Debugf("Connected to %s", p.Addr())

   // The protocol has been negotiated successfully so start processing input
   // and output messages.
   go p.stallHandler()
   go p.inHandler()
   go p.queueHandler()
   go p.outHandler()
   go p.pingHandler()

   // Send our verack message now that the IO processing machinery has started.
   p.QueueMessage(wire.NewMsgVerAck(), nil)
   return nil
}
go p.stallHandler()

节点是否失联的处理方法,维持一个deadline时间,每次连接请求会增大deadline时间

go p.inHandler()

接受消息的处理方法,收到消息会调用p.cfg.Listeners.*****(p, msg)方法

go p.queueHandler()

维护发送队列,从outputQueue通道读取放到sendQueue通道

go p.outHandler()
此方法负责从sendQueue通道读取消息,然后发送消息p.writeMessage(msg.msg, msg.encoding)

go p.pingHandler()
定时发送ping消息到outputQueue通道




本文作者:architect.bian,欢迎收藏,转载请保留原文地址并保留版权声明!谢谢~
还没完!往下看!!!





猜你喜欢

转载自blog.csdn.net/vohyeah/article/details/80752371