区块链特辑 :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();
//