比特币源码阅读:比特币网络(一)

比特币网络部分主要包含在net.cpp和netbase.cpp文件中,netbase.cpp内主要是一些辅助函数,因此我们主要阅读net.cpp文件中的几个重要函数

01:ThreadDNSAddressSeed

// src/net.cpp 
void CConnman::ThreadDNSAddressSeed()
{
    // goal: only query DNS seeds if address need is acute
    // Avoiding DNS seeds when we don't need them improves user privacy by
    //  creating fewer identifying DNS requests, reduces trust by giving seeds
    //  less influence on the network topology, and reduces traffic to the seeds.
/*该方法提示,只有在急需接入网络的时候再使用DNS seed。这样能避免DNS seed连接数过多,也能提高用户的隐私。所以尽量不要直接连接DNS seed。*/
    if ((addrman.size() > 0) &&
        (!gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) {
        if (!interruptNet.sleep_for(std::chrono::seconds(11)))
            return;

        LOCK(cs_vNodes);
        int nRelevant = 0;
        for (auto pnode : vNodes) {
            nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices);
        }
        if (nRelevant >= 2) {
            LogPrintf("P2P peers available. Skipped DNS seeding.\n");
            return;
        }
    }

    const std::vector &vSeeds = Params().DNSSeeds();
    int found = 0;

    LogPrintf("Loading addresses from DNS seeds (could take a while)\n");

    for (const CDNSSeedData &seed : vSeeds) {
        if (interruptNet) {
            return;
        }
        if (HaveNameProxy()) {
            AddOneShot(seed.host);
        } else {
            std::vector vIPs;
            std::vector vAdd;
            ServiceFlags requiredServiceBits = nRelevantServices;
            std::string host = GetDNSHost(seed, &requiredServiceBits);
            CNetAddr resolveSource;
            if (!resolveSource.SetInternal(host)) {
                continue;
            }
            if (LookupHost(host.c_str(), vIPs, 0, true))
            {
                for (const CNetAddr& ip : vIPs)
                {
                    int nOneDay = 24*3600;
                    CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
                    addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
                    vAdd.push_back(addr);
                    found++;
                }
                addrman.Add(vAdd, resolveSource);
            }
        }
    }

    LogPrintf("%d addresses found from DNS seeds\n", found);
}

将这个函数拆分成多个段落来分析。

第一段代码:

if ((addrman.size() > 0) &&
        (!gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) {
        if (!interruptNet.sleep_for(std::chrono::seconds(11)))
            return;

        LOCK(cs_vNodes);
        int nRelevant = 0;
        for (auto pnode : vNodes) {
            nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices);
        }
        if (nRelevant >= 2) {
            LogPrintf("P2P peers available. Skipped DNS seeding.\n");
            return;
        }
    }

addrman.size()函数在/src/addrman.h中声明。返回IP地址管理器CAddrMan中的IP地址个数。
-forcednsseed参数指强制通过DNSseed来接入网络。DEFAULT_FORCEDNSSEED默认是false。
interruptNet.sleep_for(std::chrono::seconds(11)线程阻塞11秒。

cs_vNodes声明在/src/net.h文件中

// src/net.h
mutable CCriticalSection cs_vNodes;

CCriticalSection类CCriticalSection的对象表示一个"临界区",它是一个用于同步的对象,同一时刻只允许一个线程存取资源或代码区。类似于互斥锁功能。
vNodes声明在/src/net.h

// src/net.h
std::vector vNodes;

系统定义了节点数组( vector vNodes),包含了连接的所有节点。当节点连接上,则把此节点添加到节点数组中;断开连接后,从节点数组中移除此节点。

这段代码的意思是:如果IP地址管理器CAddrMan中IP地址大于0,且没有指定-forcednsseed参数,线程阻塞11秒。然后锁定cs_vNodes,遍历vNodes节点数组,如果成功连接的节点个数大于等于2。则打印"P2P节点是有效的,跳过DNS seeding阶段"

剩余部分代码:

const std::vector &vSeeds = Params().DNSSeeds();
    int found = 0;

    LogPrintf("Loading addresses from DNS seeds (could take a while)\n");

    for (const CDNSSeedData &seed : vSeeds) {
        if (interruptNet) {
            return;
        }
        if (HaveNameProxy()) {
            AddOneShot(seed.host);
        } else {
            std::vector vIPs;
            std::vector vAdd;
            ServiceFlags requiredServiceBits = nRelevantServices;
            std::string host = GetDNSHost(seed, &requiredServiceBits);
            CNetAddr resolveSource;
            if (!resolveSource.SetInternal(host)) {
                continue;
            }
            if (LookupHost(host.c_str(), vIPs, 0, true))
            {
                for (const CNetAddr& ip : vIPs)
                {
                    int nOneDay = 24*3600;
                    CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
                    addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
                    vAdd.push_back(addr);
                    found++;
                }
                addrman.Add(vAdd, resolveSource);
            }
        }
    }

    LogPrintf("%d addresses found from DNS seeds\n", found);

这段代码的意思是通过DNS seed列表来获取对应的IP地址、端口号存放在IP管理器CAddrMan中。

你可能感兴趣的:(比特币源码阅读:比特币网络(一))