从零开始学习比特币开发(七):P2P网络建立流程之生成地址对并连接到指定地址

当前位置:首页 > 币圈百科 > 从零开始学习比特币开发(七):P2P网络建立流程之生成地址对并连接到指定地址

从零开始学习比特币开发(七):P2P网络建立流程之生成地址对并连接到指定地址

2023-01-09币圈百科172

本节继续讲解比特币P2P网络建立流程。本节中解释的线程是“ThreadOpenAddedConnections”,它用于生成地址对并连接到指定的地址。本文可以结合比特币系统启动第12步的讲解,让我们对比特币系统启动的过程有一个更系统的了解。

P2P网络的建立是在比特币系统启动的第12步最后时刻被调用的?CConnman:开始?方法的开始。

本节内容在?net.cpp、net_processing.cpp?在文件里等着。

下面开始解释每个线程的具体处理。

1、ThreadSocketHandler

参见文章从零开始学习比特币(5)——P2P网络建立过程中套接字的读取和发送

2、ThreadnSaddressSeed

参见文章从零开始学习比特币(6)——查询P2P网络建立过程中的DNS节点[x OpenNetworkConnection?方法连接到指定的地址。

线程是在?net.cpp?文件的1959行。先来具体解读一下。

线程的主体是一个?什么时候?流通。在循环中执行以下处理。

打电话?GetAddedNodeInfo?方法来获取所有节点信息。这个方法返回所有的节点信息,包括连接的和未连接的地址。首先,生成一个保存节点信息的容器变量?ret?并列出保存地址字符串的对象?梯子.然后呢?vAddedNodes?将集合中的所有地址复制到?穿着梯子。STD:vector ret;STD:list ladders(0);{ LOCK(cs _ vAddedNodes);ret . reserve(vaddednodes . size());std:copy(vAddedNodes.cbegin()、vAddedNodes.cend()、STD:back _ inserter(lAddresses));}遍历所有节点(vNodes?节点容器),并执行以下处理。如果当前节点的地址有效,join?mapConnected?在map中,Key是当前节点的地址,值表示当前节点是否是入站节点。获取当前节点的地址名称。名字不空就放进去?mapConnectedByName?在map中,Key是当前节点的地址名,值为?std:pair?对象,其中第一个值指示当前节点是否是入站节点,第二个值是节点的地址。STD:map map connected;STD:map

mapConnectedByName;{ LOCK(cs _ vNodes);for(const CNode * pnode:vNodes){ if(pnode-addr。is valid()){ map connected[pnode-addr]=pnode-fin bound;} STD:string addrName=pnode-get addr name();如果(!addrName . empty()){ mapConnectedByName[STD:move(addrName)]=STD:make _ pair(pnode-fInbound,static _ cast(pnode-addr));}}}遍历?lAddresses?变量,并执行以下处理。根据当前地址和当前网络类型,生成一个?服务?类型的对象?CService和一个节点信息对象。如果当前地址是IP:Port的形式,那么查?mapConnected?相应集合的地址。如果可以找到,设置节点信息对象的相关属性。

如果当前地址是以名字的形式,那么查?mapConnectedByName?相应集合的地址。如果可以找到,设置节点信息对象的相关属性。

添加当前地址信息对象?ret?收藏中。for(const STD:string stradd node:lAddresses){ CService service(lookup numeric(stradd node . c _ str(),Params()。GetDefaultPort()));AddedNodeInfo added node { stradd node,CService(),false,false };如果(服务。IsValid()) { //strAddNode是一个IP:port auto it=map connected . find(service);如果(它!=map connected . end()){ added node . resolved address=service;added node . fc connected=true;added node . fin bound=it-second;} } else { //strAddNode是一个名称auto it=mapconnectedbyname . find(stradd node);如果(它!=mapconnectedbyname . end()){ added node . resolved address=it-second . second;added node . fc connected=true;added node . fin bound=it-second . first;} } ret . launte _ back(STD:move(added node));}返回ret?集合。 遍历所有节点信息。如果当前节点没有连接,进行如下处理:生成地址对象?Addr,类型?女侍者.打电话?OpenNetworkConnection?方法连接到当前节点。for(const AddedNodeInfo info:vInfo){ if(!info.fConnected) { if(!格兰特。TryAcquire()) { //如果我们已经用完了我们的信号量并需要一个新的信号量,我们不要在这里等待,因为当我们等待的时候addednodeinfo状态可能会改变。打破;} tried=trueCAD address addr(CService(),NODE _ NONE);OpenNetworkConnection(addr,false,grant,info.strAddedNode.c_str(),false,false,true);如果(!interrupt net . sleep _ for(STD:chrono:毫秒(500)))返回;}}

下面具体看一下?OpenNetworkConnection?功能的处理。

如果呢?中断网?为真,则返回。如果网络未激活(fNetworkActive?False),则返回。if(interrupt net){ return;}如果(!fNetworkActive){ return;}如果参数?pszDest?为空(当前节点信息的地址),进一步,如果要连接的节点是本地的、连接的或禁止的,则返回。如果参数?pszDest?不为空,此外,如果节点已连接,则返回。如果(!pszDest){ if(is local(addr connect)| | FindNode(static _ cast(addr connect))| | is banned(addr connect)| | FindNode(addr connect。ToStringIPPort()))返回;} else if(FindNode(STD:string(pszDest)))返回;打电话?ConnectNode?方法,连接到指定的地址,并返回对等节点。CNode?对象。如果连接失败,它将返回。如果参数?grantOutbound?对象存在,调用它的。MoveTo?处理的方法。如果参数?fOneShot?如果为真,设置对等节点的?fOneShot?属性为真。如果是临时探测节点(参数fFeeler?True),设置对等节点的?费勒?属性为真。如果是手动连接,则设置?m _手动_连接?属性为真。调用网络事件处理程序?InitializeNode?方法初始化对等节点。具体代码在哪里?net_processing.cpp?文件的第611行,如下图:void peer logic finalization:initialize node(cnode * pnode){ c address addr=pnode-addr;STD:string addrName=pnode-get addr name();NodeId NodeId=pnode-GetId();{ LOCK(cs _ main);mapnodestate . launte _ hint(mapnodestate . end()、STD:piece _ construct、std:forward_as_tuple(nodeid)、std:forward_as_tuple(addr,STD:move(addrName)));}如果(!pnode-fin bound)pushnodevision(pnode,connman,GetTime());}

代码的主要动作是检查节点是否是出站节点,即连接到其他对等节点,如果是,调用?PushNodeVersion?方法发送版本信息。特定消息处理部分。将生成的对等节点保存到?vNodes?向量。上面解释的

从零开始学习比特币开发(七):P2P网络建立流程之生成地址对并连接到指定地址

3.1,ConnectNode

?OpenNetworkConnection?功能“3。打电话?ConnectNode?方法,连接到指定的地址,并返回对等节点。CNode?对象”,我提到了‘connect node’方法,它负责连接到特定的对等节点。我们来看看具体的治疗方法。

如果参数?pszDest?如果是空指针,处理如下:如果要连接的地址是本地地址,直接返回空指针。打电话?FindNode?方法来查看指定的节点是否存在。如果它存在,即已经连接,则返回一个空指针。if(pszDest==null ptr){ if(is local(addr connect))返回null ptr;//查找现有连接CNode * pnode=FindNode(static _ cast(addr connect));if (pnode) { LogPrintf('未能打开新连接,已连接\ n ');返回nullptr}}如果参数?pszDest?不是空指针,则调用。查找?方法来查找/生成对应于地址字符串的地址对象。如果找到,则执行以下处理:生成要连接的地址对象。如果地址address对象无效,则返回一个空指针。打电话?FindNode?方法来查找相应的地址对象。如果它存在,即已经连接,则返回一个空指针。 这个地方解析要连接的地址字符串生成要连接的地址对象const int default_port=Params().GetDefaultPort();if(PSZ目的地){ STD:vector已解析;if (Lookup(pszDest,resolved,default_port,fNameLookup!HaveNameProxy(),256)!已解决。empty()){ addr connect=CAD address(resolved[GetRand(resolved。size())],NODE _ NONE);如果(!addrConnect .IsValid()) { LogPrint(BCLog:NET,'解析程序返回了无效的地址%s(对于%s '添加连接.ToString()、PSZ dest);返回nullptr}锁(cs _ vNodes);CNode * pnode=FindNode(static _ cast(addr connect));if(pnode){ pnode-MaybeSetAddrName(STD:string(pszDest));LogPrintf('无法打开新连接ction, already connected\n"); return nullptr; } }}如果要连接的地址对象是有效的,进行下面的处理。调用?GetProxy?方法,返回代理类型。如果方法返回为真,即存在代理,那么调用?CreateSocket?方法,创建代理套接字。如果成功创建,调用?ConnectThroughProxy?方法,通过代理连接到对等蓑衣网小编2022节点。如果不存在代理,那么调用?CreateSocket?方法,创建对等节点的套接字。如果成功创建,调用?ConnectSocketDirectly?方法,直接连接到对等节点。bool proxyConnectionFailed = false;if (GetProxy(addrConnect.GetNetwork(), proxy)) { hSocket = CreateSocket(proxy.proxy); if (hSocket == INVALID_SOCKET) { return nullptr; } connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, &proxyConnectionFailed);} else { // no proxy needed (none set for target network) hSocket = CreateSocket(addrConnect); if (hSocket == INVALID_SOCKET) { return nullptr; } connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout, manual_connection);}if (!proxyConnectionFailed) { // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to // the proxy, 蓑衣网小编2022 mark this as an attempt. addrman.Attempt(addrConnect, fCountFailure);}如果要连接的字符串不空,且存在代理,那么:调用?CreateSocket?方法,生成代理的套接字。然后,调用?ConnectThroughProxy方法,通过代理连接到指定的对等节点。hSocket = CreateSocket(proxy.proxy);if (hSocket == INVALID_SOCKET) { return nullptr;}std::string host;int port = default_port;SplitHostPort(std::string(pszDest), port, host);connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, nullptr);如果以上都没有连接到主节点,则关闭套接字并返回空指针。 if (!connected) { CloseSocket(hSocket); return nullptr; }最后,生成并返回主节点对象。 NodeId id = GetNewNodeId(); uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CAddress addr_bind = GetBindAddress(hSocket); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, 蓑衣网小编2022 pszDest ? pszDest : "", false); pnode->AddRef(); return pnode;

我是区小白,Ulord全球社区联盟(优得社区)核心区块链技术开发者,深入研究比特币,以太坊,EOS Dash,Rsk,Java, Nodejs,PHP,Python,C++ 我希望能聚集更多区块链开发者,一起学习共同进步。为了更高效的交流探讨区块链开发过程中遇到的问题,欢迎将以上问题的答案在帖子下面留言。

从零开始学习比特币开发(七):P2P网络建立流程之生成地址对并连接到指定地址 | 分享给朋友: