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

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

承继前篇, 前一篇介绍了连接底层的一些细节,包括socket,握手等详细步骤,等待握手完成后,会调用startPeerSession抛向上层,这个时候连接表明已经建立了,从代码里面,为了表征这种连接的建立,会再定义一些数据结构来表达这种关系,本篇文章我们将首先去了解下startPeerSession里面都做了些什么事情,然后再去详细了解逻辑上的连接表达方式。

一、建立连接

这部分我们只介绍host.cpp中的startPeerSession函数,其他关于host的部分将在下篇中介绍,那也是整个p2p系列代码部分的最后一篇。首先研读下cpp的代码,如下

// 这是在握手成功之后被handshake调用,握手是在connect或者acceptor中进行
// 可以细致了解下这个函数的参数,_id表示对方的公钥,也是对方的节点id,rlp实际上
// 是writeHello中填写的对方的一些信息,io是数据帧编解码,_s就是底层通信的socket
void Host::startPeerSession(Public const& _id, RLP const& _rlp, unique_ptr<RLPXFrameCoder>&& _io, std::shared_ptr<RLPXSocket> const& _s)
{
    // session可能是主动或者被动建立的,所以peers和node table里面可能不包括这个node id
    shared_ptr<Peer> p;
    DEV_RECURSIVE_GUARDED(x_sessions)
    {
        if (m_peers.count(_id))   //判断peer是否存在
            p = m_peers[_id];
        else
        {
            // 不存在的话,先尝试从node table中获取端口信息
            if (Node n = nodeFromNodeTable(_id))
                p = make_shared<Peer>(n);

            if (!p)
                p = make_shared<Peer>(Node(_id, UnspecifiedNodeIPEndpoint));  //如果node_table中也没有,先不指定ip断点信息

            m_peers[_id] = p;  //添加到m_peers中去
        }
    }
    if (p->isOffline()) // 如果之前已经下线了,session不存在了
        p->m_lastConnected = std::chrono::system_clock::now();  //更新
    p->endpoint.address = _s->remoteEndpoint().address();  //更新地址

    auto protocolVersion = _rlp[0].toInt<unsigned>();  // 协议版本号
    auto clientVersion = _rlp[1].toString();           // 客户版本
    auto caps = _rlp[2].toVector<CapDesc>();           // 远方端点支持的能力
    auto listenPort = _rlp[3].toInt<unsigned short>(); // 监听的端口
    auto pub = _rlp[4].toHash<Public>();  // 公钥,与node id相同

    if (pub != _id)
    {
        cdebug << "Wrong ID: " << pub << " vs. " << _id; // 不同认为有问题,不建立session
        return;
    }

    // clang error (previously: ... << hex << caps ...)
    // "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments"
    stringstream capslog;

    // leave only highset mutually supported capability version
    // 如果当前host不支持,或者有重复,清理
    caps.erase(remove_if(caps.begin(), caps.end(), [&](CapDesc const& _r){ return !haveCapability(_r) || any_of(caps.begin(), caps.end(), [&](CapDesc const& _o){ return _r.first == _o.first && _o.second > _r.second && haveCapability(_o); }); }), caps.end());

    for (auto cap: caps)
        capslog << "(" << cap.first << "," << dec << cap.second << ")";

    cnetlog << "Hello: " << clientVersion << " V[" << protocolVersion << "]"
            << " " << _id << " " << showbase << capslog.str() << " " << dec << listenPort;

    // create session so disconnects are managed
    // session来管理连接,所以先创建session,然后再去判断信息的合法性
    shared_ptr<SessionFace> ps = make_shared<Session>(this, move(_io), _s, p, PeerSessionInfo({_id, clientVersion, p->endpoint.address.to_string(), listenPort, chrono::steady_clock::duration(), _rlp[2].toSet<CapDesc>(), 0, map<string, string>(), protocolVersion}));
    if (protocolVersion < dev::p2p::c_protocolVersion - 1)  //协议版本不一致的话断开
    {
        ps->disconnect(IncompatibleProtocol);
        return;
    }
    if (caps.empty())
    {
        ps->disconnect(UselessPeer);  //没有注册功能的话,直接断开连接
        return;
    }

    if (m_netPrefs.pin && !isRequiredPeer(_id))   //如果设置要求只接受可信的peer,但是当前不可信,也要断开
    {
        cdebug << "Unexpected identity from peer (got" << _id << ", must be one of " << m_requiredPeers << ")";
        ps->disconnect(UnexpectedIdentity);
        return;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值