以太坊源码分析之 P2P网络(六、p2p连接控制与消息处理(下))

本文深入剖析以太坊P2P网络的Host和Capability,探讨节点连接管理、消息处理流程。Host作为独立线程运行,负责节点连接和功能说明。Capability提供业务逻辑抽象,允许开发人员根据不同需求创建特定功能。文章详细阐述了从节点的Hello消息交换到 Capability的匹配、注册,以及Session的创建和消息回调处理的全过程。
摘要由CSDN通过智能技术生成

区块链特辑 :https://blog.csdn.net/fusan2004/article/details/80879343,欢迎查阅,原创作品,转载请标明!

这是p2p网络系列文章的最后一篇,前面很多篇主要都是在描述p2p的底层实现,那么p2p在整个系统中处于什么位置和提供什么功能,都将会在本篇进行一部分的总结,首先我们看下host相关代码,来了解p2p的运行模式,然后再去了解capacity的处理逻辑。

一、Host

先来看下host.h文件,对Host建立一个初步的印象。

class Host: public Worker
{
	friend class HostNodeTableHandler;
	friend class RLPXHandshake;	
	friend class Session;
	friend class HostCapabilityFace;
public:
    // 启动服务端,在给定端口进行监听
	Host(
		std::string const& _clientVersion,
		NetworkPreferences const& _n = NetworkPreferences(),
		bytesConstRef _restoreNetwork = bytesConstRef()
	);
    // 可选的构造函数,运行直接提供节点密钥,不需要重新载入网络信息
	Host(
		std::string const& _clientVersion,
		KeyPair const& _alias,
		NetworkPreferences const& _n = NetworkPreferences()
	);
    // 将会在网络处理事件时阻塞
	virtual ~Host();
    // 默认host,大家有印象的话就记得nodetable进行节点发现的时候需要预先设定几个节点来获取信息
	static std::unordered_map<Public, std::string> pocHosts();
    // 注册一个peer-capability,所有新建立的连接都将会拥有该capability
	template <class T> std::shared_ptr<T> registerCapability(std::shared_ptr<T> const& _t) { _t->m_host = this; m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = _t; return _t; }
    // 后面会分析这两个函数的区别
	template <class T> void addCapability(std::shared_ptr<T> const & _p, std::string const& _name, u256 const& _version) { m_capabilities[std::make_pair(_name, _version)] = _p; }
    //当前节点是否包含某项功能
	bool haveCapability(CapDesc const& _name) const { return m_capabilities.count(_name) != 0; }
    // 返回所有capability的desc
	CapDescs caps() const { CapDescs ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; }
	template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } }
    // 增加一个潜在的peer
	void addPeer(NodeSpec const& _s, PeerType _t);
    // 添加节点作为一个peer的候选,当节点发现到这个节点并且还有剩余额度的时候该节点被添加
	void addNode(NodeID const& _node, NodeIPEndpoint const& _endpoint);
    // 创建peer,并尝试保持该peer连接
	void requirePeer(NodeID const& _node, NodeIPEndpoint const& _endpoint);
	void requirePeer(NodeID const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort) { requirePeer(_node, NodeIPEndpoint(_addr, _udpPort, _tcpPort)); }
    // 标记peer不再被需要
	void relinquishPeer(NodeID const& _node);
    // 设置peer的理想数量
	void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
    // 设置最大接受连接数的乘法因子
	void setPeerStretch(unsigned _n) { m_stretchPeers = _n; }
	// 获取peer信息
	PeerSessionInfos peerSessionInfo() const;
    // 获取已经连接的peer数
	size_t peerCount() const;
    // 获取我们正在监听的地址
	std::string listenAddress() const { return m_tcpPublic.address().is_unspecified() ? "0.0.0.0" : m_tcpPublic.address().to_string(); }
    // 获取我们正在监听的端口
	unsigned short listenPort() const { return std::max(0, m_listenPort.load()); }
    // 序列化已知peer的set
	bytes saveNetwork() const;
	// TODO: P2P this should be combined with peers into a HostStat object of some kind; coalesce data, as it's only used for status information.
	Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; }
    // 网络设置
	NetworkPreferences const& networkPreferences() const { return m_netPrefs; }
    // 保存网络设置
	void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
    // 启动网络,
	void start();
    // 停止网络
	void stop();
	// 返回网络是否start
	bool isStarted() const { return isWorking(); }
	/// @returns our reputation manager.
	ReputationManager& repMan() { return m_repMan; }
	// 如果网络以及启动,并且具有交互性
	bool haveNetwork() const { Guard l(x_runTimer); Guard ll(x_nodeTable); return m_run && !!m_nodeTable; }
    // 确认并开启网络连接
	void startPeerSession(Public const& _id, RLP const& _hello, std::unique_ptr<RLPXFrameCoder>&& _io, std::shared_ptr<RLPXSocket> const& _s);
    // 根据id来获取session
	std::shared_ptr<SessionFace> peerSession(NodeID const& _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? m_sessions[_id].lock() : std::shared_ptr<SessionFace>(); }
    // 获取节点id
	NodeID id() const { return m_alias.pub(); }
    // 获取tcp端口的公开地址
	bi::tcp::endpoint const& tcpPublic() const { return m_tcpPublic; }
	/// Get the public endpoint information.
	std::string enode() const { return "enode://" + id().hex() + "@" + (networkPreferences().publicIPAddress.empty() ? m_tcpPublic.address().to_string() : networkPreferences().publicIPAddress) + ":" + toString(m_tcpPublic.port()); }
    // 获取节点信息
	p2p::NodeInfo nodeInfo() const { return NodeInfo(id(), (networkPreferences().publicIPAddress.empty() ? m_tcpPublic.address().to_string() : networkPreferences().publicIPAddress), m_tcpPublic.port(), m_clientVersion); }
protected:
    // 响应nodetable事件
	void onNodeTableEvent(NodeID const& _n, NodeTableEventType const& _e);

	/// Deserialise the data and populate the set of known peers.
	void restoreNetwork(bytesConstRef _b);

private:
	enum PeerSlotType { Egress, Ingress };
	
	// 不同类型的peer连接数量限制,主动连接少点,被动连接多一点
	unsigned peerSlots(PeerSlotType _type) { return _type == Egress ? m_idealPeerCount : m_idealPeerCount * m_stretchPeers; }
    // 判断是否与某个node建立了连接
	bool havePeerSession(NodeID const& _id) { return !!peerSession(_id); }
    // 确定并设置公共地址
	void determinePublic();
    // 主动连接peer
	void connect(std::shared_ptr<Peer> const& _p);
	// 如果等待和已连接的peer数量小于最大值返回true
	bool peerSlotsAvailable(PeerSlotType _type = Ingress);
	// ping已连接的peer,来更新连接信息,并在某些超时的peer断开
	void keepAlivePeers();
	// 断开在c_keepAliveTimeOut之前没有回复keepAlivePeers ping的peers
	void disconnectLatePeers();
    // 只会在startedWorking里面调用
	void runAcceptor();
    // 被worker调用
	virtual void startedWorking();
	/// Called by startedWorking. Not thread-safe; to be called only be Worker.
	void run(boost::system::error_code const& error);			///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions.
	// 运行network. Not thread-safe; to be called only by worker.
	virtual void doWork();
	//
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值