以太坊的底层p2pServer,大约可以分为三层:
1、底层:table对象、node对象,它们分别定义了底层的路由表以及本地节点的数据结构、搜索和验证;
1)database.go //封装node数据库相关操作
2)node.go //节点数据结构
3)ntp.go //同步时间
4)table.go //路由表
5)udp.go //网络相关操作2、中层:peer对象定义了远端节点、message对象开放发送接口、server对象则提供peer节点的检测、初始化、事件订阅、状态查询、启动和停止等功能;
1)dial.go //封装一个任务生成处理结构以及三种任务结构中(此处命名不太精确)
2)message.go //定义一些数据的读写接口,以及对外的Send/SendItem函数
3)peer.go //封装了Peer 包括消息读取
4)rlpx.go //内部的握手协议
5)server.go //初始化,维护Peer网络,还有一些对外的接口3、顶层:在eth/peer.go中对p2p/peer.go的peer再封装,包含了对该节点广播的更多区块链的信息,如交易、交易hash、区块以及区块头hash等。peer最终会被收集在peerset中使用。
1)eth/peer.go // 封装了peer和peerset两个结构体以及一些广播数据的方法
2)eth/handler.go // 封装了很多协议管理工具
一、p2p.Server基本结构
Server用于管理所有的peer连接:
type Server struct {
// Config包含了所有Server的配置选项,Service第一启动的时候Config未必初始化
Config
// 用于测试的hooks
newTransport func(net.Conn) transport
newPeerHook func(*Peer)
lock sync.Mutex // protects running
running bool
ntab discoverTable // 包括Self()、Close()、Resolve()、Lookup()、ReadRandomNodes()等函数的接口
listener net.Listener
ourHandshake *protoHandshake // 协议握手的RLP结构
lastLookup time.Time
DiscV5 *discv5.Network // 基于V5发现协议的topic-discovery网络
// 下面是关于peer的操作
peerOp chan peerOpFunc
peerOpDone chan struct{}
quit chan struct{}
addstatic chan *discover.Node
removestatic chan *discover.Node
addtrusted chan *discover.Node
removetrusted chan *discover.Node
posthandshake chan *conn
addpeer chan *conn
delpeer chan peerDrop
loopWG sync.WaitGroup // loop, listenLoop
peerFeed event.Feed
log log.Logger
}
再看看Server的配置:
type Config struct {
PrivateKey *ecdsa.PrivateKey `toml:"-"` // 本地节点的秘钥
MaxPeers int // 可连接的节点最大数值
// maxpendingpeer是在握手阶段中可以挂起的最大对等点数量,分别计算入站连接和出站连接。预设值的默认值为零
MaxPendingPeers int `toml:",omitempty"`
// 拨号比率控制入站与拨号连接的比率。例如:拨号比率为2允许1/2的连接被拨号。设置拨号比率为零默认为3。
DialRatio int `toml:",omitempty"`
NoDiscovery bool // NoDiscovery 用来禁用节点发现机制,常用于协议debugging
DiscoveryV5 bool `toml:",omitempty"` // DiscoveryV5 决定了是否启用topic-discovery协议
Name string `toml:"-"` // 设置节点名称
BootstrapNodes []*discover.Node // BootstrapNodes 用于建立与网络其余部分的连接。
BootstrapNodesV5 []*discv5.Node `toml:",omitempty"` // BootstrapNodesV5 用于建立与网络其余部分的V5连接。
StaticNodes []*discover.Node // 静态节点用作预先配置的连接,在断开连接时总是维护和重新连接。
TrustedNodes []*discover.Node // 可信节点被用作预先配置的连接,这些连接总是允许连接的,甚至超过对等限制。
// 连接可以被限制到某些IP网络。如果将此选项设置为非nil值,则只考虑与列表中包含的IP网络之一匹配的主机。
NetRestrict *netutil.Netlist `toml:",omitempty"`
// NodeDatabase是到数据库的路径,其中包含以前在网络中看到的活动节点
NodeDatabase string `toml:",omitempty"`
// 协议应该包含服务器支持的协议。为每个对等点启动匹配协议。
Protocols []Protocol `toml:"-"`
// 如果ListenAddr设置为非nil地址,服务器将侦听传入的连接。
// 如果端口为零,操作系统将选择一个端口。当服务器启动时,ListenAddr字段将更新实际地址。
ListenAddr string
// 如果设置为非nil值,则使用给定的NAT端口映射器使侦听端口对Internet可用。
NAT nat.Interface `toml:",omitempty"`
// 如果拨号器设置为非空值,则使用给定的拨号器拨号出站peer连接。
Dialer NodeDialer `toml:"-"`
// 如果NoDial是真的,服务器将不会拨任何节点。
NoDial bool `toml:",omitempty"`
// 如果EnableMsgEvents被设置,那么当消息发送到peer或从peer接收到时,服务器将发出PeerEvents
EnableMsgEvents bool
// 日志记录器是一个自定义日志记录器
Logger log.Logger `toml:",omitempty"`
}
配置里包括了服务可连接的节点(静态节点、信任节点、剩余节点)、节点发现机制、协议列表(包括ethereum协议)、端口控制。
二、p2p.Server的启动:sever.Start()
以太坊的启动流程可以参考之前的文章:以太坊源码解读(3)以太坊启动流程简析
<