func (srv *Server) run(dialstate dialer) {
// 准备临时变量
// 根据svr.TrustedNodes,在trusted中标记为信任
// 定义 删除任务、开始任务、安排任务 函数变量
for无限循环 {
// 执行 安排任务
select 条件判断:
:如果收到退出消息 {
// 跳出for无限循环
}
:如果收到添加静态节点消息 {
// 调用dialer.addStatic接口,将节点信息添加到静态节点信息map中
}
:如果收到移除静态节点消息 {
// 调用dialer.removeStatic接口
// 如果节点已经连接成功,则得到peer对象,断开连接
}
:如果收到获取peer信息的消息 {
// 调用收到的回调函数,将当前peers作为参数传入
}
:如果收到任务完成消息 {
// 调用dialer.taskDone函数,更新dialer状态(拨号任务:在拨号间隔时间保护对象中,添加当前完成节点信息,从正在拨号节点信息记录中删除当前完成节点信息;discover任务:lookupRunning置为false,查找结果追加到lookupBuf中)
// 调用本地delTask函数,从本地runningTasks中删除
}
:如果收到加密握手成功消息 {
// 验证加密握手(如果非信任非静态非storeman,而且已连接peers数量达到MaxPeers,则返回节点过多错误;如果peers包含当前握手节点,则返回以存在错误;如果是自身,则返回自身节点错误fuze返回nil)
// 将验证结果发送给conn
}
:如果收到协议握手成功消息 {
// 验证协议握手(远端协议与本地支持协议有匹配,并且加密握手验证通过)
// 如果验证通过,则根据conn信息创建peer实例,添加到peers中,创建新协程运行server.runPeer(),激活新peer
// 验证结果发送给conn
}
:如果收到peer断开连接消息 {
// 将node从peers中删除
}
}
// 结束收尾
// 关闭discover
// 关闭discoverV5
// 逐个peers断开连接
// 等待所有peers断开连接回应
}
func (p *Peer) run() (remoteRequested bool, err error) {
// 准备局部变量
// 启动新协程,使用for无限循环读取peer网络消息(peer.readLoop)
// 启动新协程,使用for无限循环+定时器,向peer远端发送心跳消息(peer.pingLoop)
// 启动所有协议handlers???
for无限循环 {
select条件判断:
: 如果收到网络发送完成消息 {
// 则再设置一个网络发送消息到writeStart
}
: 如果收到一个网络接收错误消息 {
// 处理错误,退出for无限循环
}
: 如果收到一个协议错误消息 {
// 处理错误,退出for无限循环
}
: 如果收到一个断开连接消息 {
// 退出for无限循环
}
}
// 结尾处理
}
func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task {
// 记录s的起始时间
// 记录配置的对大动态拨号个数()
needDynDials := s.maxDynDials // (srv.MaxPeers + 1) / 2
// 统计peers(已连接)中标记动态拨号的个数,从needDynDials中减去
// 统计正在拨号的节点个数,从needDynDials中减去
// 从拨号历史记录中,删除已经过期的记录
// 从静态节点拨号任务信息中查找可用信息(没有正在拨号中、没有对应的peer对象、不是自身节点、如果配置白名单但是不在白名单内、不在拨号时间间隔保护期内),添加到newtasks中,并从needDynDials减去名额
// 从storeman节点拨号任务信息中查找可用信息(没有正在拨号中、没有对应的peer对象、不是自身节点、如果配置白名单但是不在白名单内、不在拨号时间间隔保护期内),添加到newtasks中,并从needDynDials减去名额
// 如果已连接成功的节点(peers)数为0,并且设置的boostnode不为空,并且尚有剩余动态拨号名额(needDynDials),并且s启动时间到现在已经超过fallback期限,则添加boostnodes第一个节点拨号任务到newtasks,同时将第一个boostnodes节点信息移至最后一位,并从needDynDials减去名额
// 剩余动态拨号任务名额数除以2,为随机候选人名额数(randomCandidates)
// 从自动查询器查询到的节点信息中,随机选取randomCandidates个,添加到newtasks,并从needDynDials减去名额
// 把lookupBuf中的节点添加到newtasks,needDynDials减去名额,并且从lookupBuf中清除
// 如果lookupBuf中的数据量不足,并且s.loopupRunning为false,则添加一个discoverTask到newtasks,并且设置s.loopupRunning为true
// 如果正在运行的task数量不为0,并且newtasks长度为0,但是保护期历史记录信息个数不为0,则在newtasks中添加一个等待超时任务(waitExpireTask)
// 返回newtasks
}
func (t *dialTask) Do(srv *Server) {
// 检测目标node的信息是否完整(是否有ip)
// 如果不完整,则调用dialTask.resolve来确定node的ip(内部依赖discoverTable.Resolve,通过网络向其他节点查询目标node的ip信息)
// 调用dialTask.dial函数进行拨号连接
// 如果拨号失败,并且node是静态node或storeman node,则尝试一次重新resolve和拨号
}
func (t *dialTask) dial(srv *Server, dest *discover.Node) bool {
// 根据node信息,建立网络连接
// 根据连接对象,创建可计量连接对象
// 调用server.SetupConn接口,与远端node进行handshake,并且新增一个peer对象
}
func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *discover.Node) {
// RLPx 加密握手(encryption handshake,依赖rlpx.doEncHandshake)
// 向p2p.server发送加密握手成功消息,等待返回结果
// RLPx协议握手(protocol handshake,依赖rlpx.doProtoHandshake)
// 向p2p.server发送协议握手成功消息,等待返回结果
}
func (srv *Server) listenLoop() {
// 计算同时最多接收连接的个数
// 创建连接个数控制器,通过chan控制接收连接的个数
for 无限循环 {
// 消耗一个连接个数名额
for 无限循环 {
// 调用accept接受外部连接
// 如果收到有效连接,则跳出无限循环
}
// 如果设置了网络受限,则检测远端ip是否在白名单内
// 根据新的连接对象,创建一个计量连接对象
// 创建新协程,在其内调用server.SetupConn端口,先进行handshake,然后新增一个新的peer对象
}
}
func (p *Peer) readLoop(errc chan<- error) {
defer p.wg.Done()
for {
msg, err := p.rw.ReadMsg()
if err != nil {
errc <- err
return
}
msg.ReceivedAt = time.Now()
if err = p.handle(msg); err != nil {
errc <- err
return
}
}
}
func (p *Peer) handle(msg Msg) error {
......
select {
case proto.in <- msg:
return nil
case <-p.closed:
return io.EOF
}
}
return nil
}
func (sm *Storeman) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
......
for {
// fetch the next packet
packet, err := rw.ReadMsg()
......
}
}
func (rw *protoRW) ReadMsg() (Msg, error) {
select {
case msg := <-rw.in:
msg.Code -= rw.offset
return msg, nil
case <-rw.closed:
return Msg{}, io.EOF
}
}
func New(cfg *Config, accountManager *accounts.Manager, aKID, secretKey, region string) *Storeman {
storeman := &Storeman{
peers: make(map[discover.NodeID]*Peer),
quit: make(chan struct{}),
cfg: cfg,
}
......
storeman.protocol = p2p.Protocol{
Name: mpcprotocol.ProtocolName,
Version: uint(mpcprotocol.ProtocolVersion),
Length: mpcprotocol.NumberOfMessageCodes,
Run: storeman.HandlePeer,
NodeInfo: func() interface{} {
return map[string]interface{}{
"version": mpcprotocol.ProtocolVersionStr,
}
},
}
return storeman
}
func (n *Node) Start() error {
......
// Gather the protocols and start the freshly assembled P2P server
for _, service := range services {
running.Protocols = append(running.Protocols, service.Protocols()...)
}
if err := running.Start(); err != nil {
return convertFileLockError(err)
}
......
}
func (sm *Storeman) Protocols() []p2p.Protocol {
return []p2p.Protocol{sm.protocol}
}
func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) {
p.wg.Add(len(p.running))
for _, proto := range p.running {
......
go func() {
err := proto.Run(p, rw)
if err == nil {
p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version))
err = errProtocolReturned
} else if err != io.EOF {
p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err)
}
p.protoErr <- err
p.wg.Done()
}()
}
}
完毕