区块链特辑 :https://blog.csdn.net/fusan2004/article/details/80879343,欢迎查阅,原创作品,转载请标明!
这周工作有点小忙,部门区块链基础平台的开发开始进入节奏了,和上一篇间隔间隔有点久了,以后还是要坚持,不能刚开始就犯毛病了。上篇讲的是以太坊p2p网络的一个重点部分——节点发现,在介绍的时候提过,节点发现是通过udp的方式来进行的,这一篇就介绍下udp通信的详细细节,这部分不是很多,算是个过渡吧。
回头再看下NodeTable类,可以看到这个类继承了UDPSocketEvents类,也就是这里和udp通信建立了关联,下面我们先看下这个类都干了些啥。。。
struct UDPSocketEvents
{
virtual ~UDPSocketEvents() = default;
virtual void onDisconnected(UDPSocketFace*) {}
virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0;
};
可以看到,这个类只提供了两个api接口,分别是onDisconnected和onReceived,其中onDisconnected有一个定义,空的函数体,在看代码的时候也能发现这个函数目前的代码并没有起到什么作用,可暂时忽略;另外的onReceived是一个纯虚函数,也就意味着NodeTable必须要实现这个函数,再回头去看NodeTable类中关于这个函数的详细编码,可以看到这是整个NodeTable更新发现的重要起点,也就是在这里解析了前面所描述的ping\pong\findnode\neighbours这四类消息,具体这四类消息,我们后面再细说,现在继续说说UDPSocketEvents是如何跟udp关联上的,看看NodeTable的构造函数实现。。。
NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled):
m_node(Node(_alias.pub(), _endpoint)),
m_secret(_alias.secret()),
m_socket(make_shared<NodeSocket>(_io, *reinterpret_cast<UDPSocketEvents*>(this), (bi::udp::endpoint)m_node.endpoint)),
m_socketPointer(m_socket.get()),
m_timers(_io)
{
for (unsigned i = 0; i < s_bins; i++)
m_state[i].distance = i;
if (!_enabled)
return;
try
{
m_socketPointer->connect(); //开启连接,这时候就可以接受外界发来的消息了,m_socketPointer指定了回调句柄就是NodeTable
doDiscovery(); //节点发现
}
catch (std::exception const& _e)
{
cwarn << "Exception connecting NodeTable socket: " << _e.what();
cwarn << "Discovery disabled.";
}
}
可以看到m_socket就是一个NodeSocket的实例,这个NodeSocket的构造函数中需要this指针传递,后面都将通过这个指针完成onReceived的回调,逻辑很清晰啦,继续看下NodeSocket吧。。。
template <typename Handler, unsigned MaxDatagramSize>
class UDPSocket: UDPSocketFace, public std::enable_shared_from_this<UDPSocket<Handler, MaxDatagramSize>>
{
public:
enum { maxDatagramSize = MaxDatagramSize };
static_assert((unsigned)maxDatagramSize < 65507u, "UDP datagrams cannot be larger than 65507 bytes");
/// Create socket for specific endpoint.
//为指定的endpoint创建socket
UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, bi::udp::endpoint _endpoint): m_host(_host), m_endpoint(_endpoint), m_socket(_io) { m_started.store(false); m_closed.store(true); };
/// Create socket which listens to all ports.
UD