以太坊源码分析之 P2P网络(三、UDP底层通信)

本文深入探讨了以太坊P2P网络中UDP通信的细节,从NodeTable类开始,分析了UDP连接、接受和发送的全过程。文章介绍了UDPSocketEvents类的onDisconnected和onReceived函数,以及NodeSocket的构造和工作原理。通过讲解UDP的异步读事件、数据校验和消息队列管理,展示了如何处理ping、pong、findnode和neighbours四种消息类型。此外,还提到了RLP编码在消息编解码中的应用和签名操作。
摘要由CSDN通过智能技术生成

区块链特辑 :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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值