从Host类到Session类
上一节我们跟踪到了Host::startPeerSession()
函数里,现在我们来深入这个函数看个究竟。
void Host::startPeerSession(Public const& _id, RLP const& _rlp, unique_ptr&& _io, std::shared_ptr const& _s)
{
// session maybe ingress or egress so m_peers and node table entries may not exist
shared_ptr p;
// ...
// create session so disconnects are managed
shared_ptr ps = make_shared(this, move(_io), _s, p, PeerSessionInfo({_id, clientVersion, p->endpoint.address.to_string(), listenPort, chrono::steady_clock::duration(), _rlp[2].toSet(), 0, map(), protocolVersion}));
// ...
{
RecursiveGuard l(x_sessions);
// ...
unsigned offset = (unsigned)UserPacket;
// todo: mutex Session::m_capabilities and move for(:caps) out of mutex.
for (auto const& i: caps)
{
auto pcap = m_capabilities[i];
if (!pcap)
return ps->disconnect(IncompatibleProtocol);
pcap->newPeerCapability(ps, offset, i); // 重要!
offset += pcap->messageCount();
}
ps->start();
m_sessions[_id] = ps;
}
LOG(m_logger) << "p2p.host.peer.register " << _id;
}
可以看到这个函数里先是创建了一个Session
类,然后对m_capabilities
的成员调用newPeerCapability()
来为每一个session
创建一个capability
,也就是消息处理器,最后调用session
类的start()
函数。
看到这里可能读者会一头雾水,不知道这里是做了什么处理,不用急,我们还是先从m_capabilities
谈起。
m_capabilities
定义在Host
类中:
std::map> m_capabilities;
CapDesc定义为:
using CapDesc = std::pair;
HostCapabilityFace
是一个虚基类,最重要的成员有两个:
class HostCapabilityFace
{
public:
// ...
virtual unsigned messageCount() const = 0;
virtual std::shared_ptr newPeerCapability(
std::shared_ptr const& _s, unsigned _idOffset, CapDesc const& _cap) = 0;
// ...
};
这两个函数正是在Host::startPeerSession()
函数中被调用的那两个!
目前我们还不清楚这两个函数的具体功能,我们需要去找HostCapabilityFace
类的子类,看看它们的实现。
为了找子类,我们需要找m_capabilities
在哪里插入数据,发现是在Host::registerCapability()
函数中
void Host::registerCapability(std::shared_ptr const& _cap)
{
registerCapability(_cap, _cap->name(), _cap->version());
}
void Host::registerCapability(
std::shared_ptr const& _cap, std::string const& _name, u256 const& _version)
{
m_capabilities[std::make_pair(_name, _version)] = _cap;
}
再找Host::registerCapability()
在哪里被调用,找到libethereum\client.cpp
里的Client::init()
,里面有一段代码:
auto ethHostCapability =
make_shared(_extNet, bc(), m_stateDB, m_tq, m_bq, _networkId);
_extNet.registerCapability(ethHostCapability);
_extNet
就是Host
对象,原来HostCapabilityFace
类的子类是EthereumHost
类。EthereumHost
类也是一个非常重要的类,我们后面再谈,这个类的定义有点意思,我们先来看看:
class EthereumHost: public p2p::HostCapability, Worker
可以看到这个类除了从Worker
类继承外,还继承了 p2p::HostCapability
类。一下子又引入了两个新类。
一个一个来,我们先来看看 p2p::HostCapability
类定义:
template
class HostCapability: public HostCapabilityFace
{
public:
// ...
unsigned messageCount() const override { return PeerCap::messageCount(); }
std::shared_ptr newPeerCapability(
std::shared_ptr const& _s, unsigned _idOffset, CapDesc const& _cap) override
{
auto p = std::make_shared(_s, this, _idOffset, _cap);
_s->registerCapability(_cap, p);
return p;
}
// ...
};
原来HostCapability<>
类才是HostCapabilityFace
类的直接子类,EthereumHost
类是HostCapabilityFace
类的孙子类。messageCount()
和newPeerCapability()
这两个函数在HostCapability<>
类里有一份实现。而且这个类是一个模板类,messageCount()
只是调用了模板参数PeerCap
的messageCount()
函数。newPeerCapability()
函数只是创建一个PeerCap
对象,并调用其registerCapability()
函数。
对于EthereumHost
类,模板参数PeerCap
就是EthereumPeer
,这点可以从EthereumHost
类定义中得到,因此在EthereumHost
类里,这两个函数相当于:
unsigned EthereumHost::messageCount() const override { return EthereumPeer::messageCount(); }
std::shared_ptr EthereumHost::newPeerCapability(
std::shared_ptr const& _s, unsigned _idOffset, CapDesc const& _cap) override
{
auto p = std::make_shared(_s, this, _idOffset, _cap);
_s->registerCapability(_cap, p);
return p;
}
先来看newPeerCapability
这个函数吧,它创建了一个EthereumPeer
类对象,并调用SessionFace::registerCapability()
注册了该对象,也就是把EthereumPeer
类对象放到了Session
类对象里,EthereumPeer
类是Session
消息处理器。
实际上EthereumHost
类自身对newPeerCapability()
函数也有自己的实现,这个实现与父类HostCapability<>
的实现稍有不同,这个后面再谈。
messageCount()
函数简单返回了一个消息数量,这个用来将不同的HostCapabilityFace
的消息错开,方便消息分发,每个HostCapabilityFace
处理某一段范围内的消息。