addPeer操作解析
来源:互联网 发布:虚拟按键软件代码 编辑:程序博客网 时间:2024/06/06 06:56
从handle(peer)倒推,寻找被调用关系
在p2p.Server.run()
函数,无限for
循环中,执行select
中case c := <-srv.addpeer:
分支的操作,进行handshake
,并且goroutine
启动Server.runPeer()
,并进一步调用peer.run()
,最终在startProtocols()
中调用proto.Run(p,rw)
,该Run()函数为handler.go
中NewProtocolManager()
中的函数类型变量Run
,该变量最终调用handle(peer)
,最终进行peer的其他操作。
node.Start() >> server.Start() >> Server.run() >> go, Server.runPeer() >> peer.run() >> startProtocols() >> proto.Run(p,rw)
p2p
中的Server
的成员变量addpeer
为conn
类型的channel
,在Server.checkpoint(c,srv.addpeer)
中的select
选择执行srv.addpeer <- c
,而checkpoint()
函数仅在Server.SetupConn()
中被调用,而SetupConn()
在Server.listenLoop()
中被调用,listenLoop()
函数中包含我们之前进行admin.addPeer()
所用到的enode
信息,由server.makeSelf()
函数生成
server.Start() >> startListening() >> go,listenLoop() >> SetupConn() >> checkpoint(),`srv.addpeer <- c`
server.Start()
函数,首先初始化server
的成员变量,包含addpeer
、addstatic
等各种channel
;然后根据server
继承config
中的各种XXDiscovery
进行各自的操作。
==========================================================================
从admin.addPeer()正推,找调用关系
命令行运行admin.addPeer()
实际调用node/api.go
中的AddPeer(url)
,该函数根据url
初始化一个p2p/discover.Node
,然后调用p2p.server.AddPeer(node)
,最终返回true
p2p.server.AddPeer(node)
仅包含一个select
语句,将node
发送到srv.addstatic
,该channel
是p2p.Server
的一个discover.Node
类型的成员变量,定义如下:
// Node represents a host on the network. The fields of Node may not be modified.type Node struct { IP net.IP // len 4 for IPv4 or 16 for IPv6 UDP, TCP uint16 // port numbers ID NodeID // the node's public key // This is a cached copy of sha3(ID) which is used for node distance calculations. // This is part of Node in order to make it possible to write tests that need a node at a certain distance. // In those tests, the content of sha will not actually correspond with ID. sha common.Hash // whether this node is currently being pinged in order to replace it in a bucket contested bool}
在p2p.Server.Run()
函数,无限for
循环中,执行select
中case n := <-srv.addstatic:
分支的操作,调用dialstate.addStatic(n)
,该方法是dialer
接口的一个方法,由p2p/dial.go
中的dialstate
实现,该函数仅执行s.static[n.ID] = &dialTask{flags: staticDialedConn, dest: n}
,dialTask
的结构体如下:
// A dialTask is generated for each node that is dialed. Its fields cannot be accessed while the task is running.type dialTask struct { flags connFlag dest *discover.Node lastResolved time.Time resolveDelay time.Duration}
s.static
在同一文件中的newTasks()
中被使用,该函数中通过for
循环遍历s.static
,然后针对每一个static
,调用s.checkDial(t.dest, peers)
进行连接检查,若没有错误产生,则会将static
添加到newtasks
中,另外,newTasks()
函数的返回值为newtasks
.
newTasks()
函数在Server.run()
中在函数类型变量scheduleTasks
中被调用,newTasks()
的返回值newtasks
随后作为startTasks()
的参数,startTasks()
会根据每个task
的类型,goroutine
启动Do(server)
函数;而scheduleTasks()
在随后的无限for
循环中被调用。
Server.run() >> for, scheduleTasks() >> newTasks() ==> startTasks() >> task.Do()
由于admin.addPeer
生成的task
为dialTask
,所以在startTasks()
中调用的Do()
函数如下:
func (t *dialTask) Do(srv *Server) { if t.dest.Incomplete() { //=>IP为nil if !t.resolve(srv) { return } } success := t.dial(srv, t.dest) //=>尝试实际连接 // Try resolving the ID of static nodes if dialing failed. if !success && t.flags&staticDialedConn != 0 { if t.resolve(srv) { t.dial(srv, t.dest) } }}
该函数调用dial()
尝试实际连接,dial()
函数如下:
func (t *dialTask) dial(srv *Server, dest *discover.Node) bool { fd, err := srv.Dialer.Dial(dest) //=>fd为net.Conn类型 if err != nil { log.Trace("Dial error", "task", t, "err", err) return false } mfd := newMeteredConn(fd, false) srv.SetupConn(mfd, t.flags, dest) return true}
dial()
函数调用srv.Dialer.Dial(dest)
,该方法由func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error){}
实现,建立一个TCP连接,其后会调用go语言库函数,不再深究,如下:
// Dial creates a TCP connection to the nodefunc (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) { addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)} return t.Dialer.Dial("tcp", addr.String()) //=> 该函数位于/usr/lib/go/src/net/dial.go,为go语言库函数}
随后,dial()
函数调用srv.SetupConn(mfd, t.flags, dest)
,如下:
SetupConn runs the handshakes and attempts to add the connection as a peer. It returns when the connection has been added as a peer or the handshakes have failed.
func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *discover.Node) { // Prevent leftover pending conns from entering the handshake. ... 初始化handshake连接c,类型为conn // Run the encryption handshake. ... 调用rlpx.go中的doEncHandshake(srv.PrivateKey, dialDest) // For dialed connections, check that the remote public key matches. ... 判断是否匹配 ... 调用srv.checkpoint(c, srv.posthandshake),与“从handle(peer)倒推,寻找被调用关系”中的checkpoint()为同一个函数, 但是参数不同,srv.posthandshake为channel,表示conn已通过encHandShake(身份已知,但是尚未验证) // Run the protocol handshake ... 调用c.doProtoHandshake(srv.ourHandshake),该函数会通过p2p.Send(),发送handshakeMsg标识的消息; 然后,调用readProtocolHandshake()读取接收到的handshakeMsg标识消息。(该标识和pbftMessage标识类似) c.caps, c.name = phs.Caps, phs.Name ... 调用srv.checkpoint(c, srv.addpeer),与“从handle(peer)倒推,寻找被调用关系”中的checkpoint()为同一个函数, 参数也完全相同,其后操作见上文。 // If the checks completed successfully, runPeer has now been launched by run.}
- addPeer操作解析
- XML解析--DOM解析操作
- DOM XML解析操作
- 二进制操作解析
- js操作语言解析
- java 字符串解析操作
- PV 操作解析
- 重载操作符解析
- NSOperation操作解析
- PV操作 解析
- Dom解析操作源代码
- PV操作例题解析
- sax解析操作XML
- 重载操作符解析
- gcd 简单操作解析
- Android多线程操作解析
- Integer执行++操作解析
- 异常操作(解析文件)
- bos项目day04区域条件查询:报错ERROR DefaultDispatcherErrorHandler:42
- 入门Webpack
- [Tensorflow]L2正则化和collection【tf.GraphKeys】
- 面向对象思想的理解
- Codeforces Round #447 (Div. 2) A. QAQ 暴力
- addPeer操作解析
- 无监督特征学习基本原理
- (转)区块链:CITA
- 学生排队
- 推箱子
- erlang gen_fsm源码分析
- Selenium--显示等待和隐式等待
- C语言操作符的介绍及总结
- Jupyter notebook和pandas的基本使用