在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 represents a host on the network. The fields of Node may not be modified.typeNodestruct { 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的结构体如下:
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.
// 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
}
Server.run() >> for, scheduleTasks() >> newTasks() ==> startTasks() >> task.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 creates a TCP connection to the node
func (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语言库函数
}
// 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.