emule中节点加入Kad网络过程(源代码详解)
EmuleDlg.cpp中函数BOOL CemuleDlg::OnInitDialog(),此函数用于对话框的初始化,在这个函数里添加了定时器:VERIFY( (m_hTimer = ::SetTimer(NULL, NULL, 300, StartupTimer)) != NULL );
在这里添加了函数void CALLBACK CemuleDlg::StartupTimer(HWND /*hwnd*/, UINT /*uiMsg*/, UINT /*idEvent*/, DWORD /*dwTime*/),
case 2:
theApp.Kad_Dlg->status++;
if(!theApp.listensocket->StartListening())
ASSERT(0);
if(!theApp.clientudp->Create())
ASSERT(0);
theApp.Kad_Dlg->status++;
break;
在StartupTimer这个函数里,添加了一个ListenSocket的侦听端,并且在本地节点创建了一个CClientUDPSocket* clientudp;
然后程序启动。
顺便说一句,在CEmule类中定义了许多的类的实例,这都在今后使用到:
UploadBandwidthThrottler* uploadBandwidthThrottler;
CClientList* clientlist;
CClientUDPSocket* clientudp;
CListenSocket* listensocket;
CSharedFileList* sharedfiles;
CDownloadQueue* downloadqueue;
CUploadQueue* uploadqueue;
CServerList* serverlist;
LastCommonRouteFinder* lastCommonRouteFinder;
CServerConnect* serverconnect;
CIPFilter* ipfilter;
CClientCreditsList* clientcredits;
CSearchList* searchlist;
CKnownFileList* knownfiles;
CMMServer* mmserver;
AppState m_app_state; // defines application state for shutdown
CMutex hashing_mut;
CString m_strCurVersionLong;
CPeerCacheFinder* m_pPeerCache;
CFriendList* friendlist;
CFirewallOpener* m_pFirewallOpener;//hyper added
节点加入网络:
Emule连接Kad网络时,调用函数:Kademlia::CKademlia::Start(); Start()这个函数没有做什么实际意义上的事情,主要是new了几个类:
m_pInstance = new CKademlia();
m_pInstance->m_pPrefs = pPrefs;
m_pInstance->m_pUDPListener = NULL;
m_pInstance->m_pRoutingZone = NULL;
m_pInstance->m_pIndexed = new CIndexed();
m_pInstance->m_pRoutingZone = new CRoutingZone();
m_pInstance->m_pUDPListener = new CKademliaUDPListener();
并且更改了几个定时器的时间。
接着程序转入到routingzone.cpp中执行。
在上面那部分的Start ()函数体内部初始化了CRoutingZone这个类,这个类的构造函数CRoutingZone::CRoutingZone()体中调用函数Init(NULL, 0, CUInt128((ULONG)0));来初始化根节点(应该就是本地节点)。
在void CRoutingZone::Init(CRoutingZone *pSuper_zone, int iLevel, const CUInt128 &uZone_index)函数体内部创建了一个新的m_pBin = new CRoutingBin();接着调用函数StartTime(),用来开始这个区域。在StartTime()函数内部添加事件CKademlia::AddEvent(this);
在调用完函数StartTime()函数后,从文件中读取以前保存的联系人。
在调用完函数Kademlia::CKademlia::Start();之后,Kademlia开始处理,转入函数Kademlia::CKademlia::Process()开始执行,在函数void CKademlia::Process()中调用函数pZone->OnSmallTimer();即CRoutingZone中OnSmallTimer().。
CRoutingZone中OnSmallTimer(),在此函数体内,当判断联系人为非空时,调用函数CKademlia::GetUDPListener()->SendMyDetails_KADEMLIA2(KADEMLIA2_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort());来发送本地节点的一些信息,其中函数的第一个参数是消息的类型,KADEMLIA2_HELLO_REQ表明是Kademlia 2.0网络的加入请求,相当于TCP/IP中的ACK,即表明这个消息是用来加入网络的。第二个参数是本地节点的IP,第三个节点是本地节点的端口。
接着转入KademliaUDPListener.cpp中函数void CKademliaUDPListener::SendMyDetails_KADEMLIA2(byte byOpcode, uint32 uIP, uint16 uUDPPort)运行,主要是调用函数SendPacket(byPacket, uLen, uIP, uUDPPort);,SendPacket(byPacket, uLen, uIP, uUDPPort);函数在KademliaUDPListener.cpp内部,此函数体内部调用函数theApp.clientudp->SendPacket(pPacket, ntohl(uDestinationHost), uDestinationPort);来发送包。
ClientUDPSocket.cpp中函数theApp.clientudp->SendPacket(pPacket, ntohl(uDestinationHost), uDestinationPort);体内部将刚才的消息包(或者叫数据包)加入到controlpacket_queue的队尾,controlpacket_queue.AddTail(newpending); controlpacket_queue是一个链表,类型是CTypedPtrList<CPtrList, UDPPack*> controlpacket_queue;,是通过模板来实现的。接着继续调用函数theApp.uploadBandwidthThrottler->QueueForSendingControlPacket(this);此时数据包在链表UploadBandwidthThrottler* uploadBandwidthThrottler;中排队。
类UploadBandwidthThrottler继承自CWinThread类,主要是作为线程来运行的。类在初始化,在构造函数中调用函数UINT AFX_CDECL UploadBandwidthThrottler::RunProc(LPVOID pParam),这个函数调用uploadBandwidthThrottler->RunInternal();,RunInternal()函数主要用来发送来自socket的数据包,函数体内调用两个函数:
SocketSentBytes socketSentBytes = socket->SendControlData(allowedDataRate > 0?(UINT)(bytesToSpend - spentBytes):1, minFragSize);
以及
SocketSentBytes socketSentBytes = socket->SendFileAndControlData(neededBytes, minFragSize);
其中的socket类型是ThrottledFileSocket*,在类ThrottledFileSocket中这两个函数被定义为虚函数,而且在这个类内部没有具体实现,它们的实现在类CClientUDPSocket中,类CClientUDPSocket继承自CAsyncSocket以及ThrottledControlSocket,如下代码:
class CClientUDPSocket : public CAsyncSocket, public ThrottledControlSocket // ZZ:UploadBandWithThrottler (UDP)。
socket->SendControlData(allowedDataRate > 0?(UINT)(bytesToSpend - spentBytes):1, minFragSize);
以及
SocketSentBytes socketSentBytes = socket->SendFileAndControlData(neededBytes, minFragSize);的实现体在ClientUDPSocket.cpp中424行:
SocketSentBytes CClientUDPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 /*minFragSize*/){ // ZZ:UploadBandWithThrottler (UDP)
在它们内部调用了函数SendTo,if (!SendTo(sendbuffer, cur_packet->packet->size+2, cur_packet->dwIP, cur_packet->nPort))(在ClientUDPSocket.cpp中440行)。这个函数是类CClientUDPSocket的成员函数。int CClientUDPSocket::SendTo(char* lpBuf,int nBufLen,uint32 dwIP, uint16 nPort),在这个函数体内调用类CAsyncSocket的成员函数uint32 result = CAsyncSocket::SendTo(lpBuf,nBufLen,nPort,ipstr(dwIP));,类CAsyncSocket是MFC的类库中的一个类。
至此,本地节点加入网络的请求就发送完毕。
下面讲述本地节点在接收到来自其他节点的回应后在本地采取的一些措施从而把自己加入到网络内。
当网络事件发生时(即本地网卡接收到数据包),“socket窗口”接收WM_SOCKET_NOTIFY消息,消息处理函数OnSocketNotify被调用,。“socket窗口”的定义和消息处理是MFC实现的,其中OnSocketNotify函数定义如下:
LRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam)
{
CSocket::AuxQueueAdd(WM_SOCKET_NOTIFY, wParam, lParam);
CSocket::ProcessAuxQueue();
return 0L;
}
在CSocket::ProcessAuxQueue();函数中回调CAsyncSocket的成员函数DoCallBack,DoCallBack调用事件处理函数OnReceive。
int PASCAL CSocket::ProcessAuxQueue()
{
……………………//省略部分
if (pMsg->message == WM_SOCKET_NOTIFY)
{
CAsyncSocket::DoCallBack(pMsg->wParam, pMsg->lParam);
}
………………//省略部分
return nCount;
}
void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
{
……………………//省略部分
pSocket->OnReceive(nErrorCode);
/*pSocket类型是:CClientUDPSocket,因为类CClientUDPSocket继承了类CAsyncSocket,而OnReceive在CAsyncSocket定义的虚函数,OnReceive在CClientUDPSocket中重新做了实现,因此调用的时候会转到CClientUDPSocket中OnReceive执行。*/
}
void CClientUDPSocket::OnReceive(int nErrorCode)
{
……………………
case OP_KADEMLIAHEADER:
{
// theStats.AddDownDataOverheadKad(length);
if (length >= 2)
Kademlia::CKademlia::ProcessPacket(buffer, length, ntohl(sockAddr.sin_addr.S_un.S_addr), ntohs(sockAddr.sin_port));
else
throw CString(_T("Kad packet too short"));
break;
}
……………………
}
接着调用在kademlia.cpp中定义的函数ProcessPacket。
void CKademlia::ProcessPacket(const byte *pbyData, uint32 uLenData, uint32 uIP, uint16 uPort)
{
if( m_pInstance && m_pInstance->m_pUDPListener )
m_pInstance->m_pUDPListener->ProcessPacket( pbyData, uLenData, uIP, uPort);
}
转入KademliaUDPListener类中ProcessPacket函数运行。
void CKademliaUDPListener::ProcessPacket(const byte* pbyData, uint32 uLenData, uint32 uIP, uint16 uUDPPort)
{
//………………………………省略部分
switch (byOpcode)
{
………………………………//省略部分
case KADEMLIA_RES:
if (thePrefs.GetDebugClientKadUDPLevel() > 0)
DebugRecv("KADEMLIA_RES", uIP, uUDPPort);
Process_KADEMLIA_RES(pbyPacketData, uLenPacket, uIP, uUDPPort);
break;
………………………………//省略部分
}
}
转入函数Process_KADEMLIA_RES(pbyPacketData, uLenPacket, uIP, uUDPPort);执行:
void CKademliaUDPListener::Process_KADEMLIA_RES (const byte *pbyPacketData, uint32 uLenPacket, uint32 uIP, uint16 uUDPPort)
{
//……………………
if(CKademlia::GetPrefs()->GetRecheckIP())
{
FirewalledCheck(uIP, uUDPPort);
if (thePrefs.GetDebugClientKadUDPLevel() > 0)
DebugSend("KADEMLIA_HELLO_REQ", uIP, uUDPPort);
SendMyDetails(KADEMLIA_HELLO_REQ, uIP, uUDPPort);
}
if(::IsGoodIPPort(ntohl(uIPResult),uUDPPortResult))
{
pRoutingZone->Add(uIDResult, uIPResult, uUDPPortResult, uTCPPortResult, 0);
pResults->push_back(new CContact(uIDResult, uIPResult, uUDPPortResult, uTCPPortResult, uTarget, 0));
}
}
}
CSearchManager::ProcessResponse(uTarget, uIP, uUDPPort, pResults);
}
在这个函数体内部主要包括对4个函数的调用,分别是:
SendMyDetails(KADEMLIA_HELLO_REQ, uIP, uUDPPort);
pRoutingZone->Add(uIDResult, uIPResult, uUDPPortResult, uTCPPortResult, 0);
pResults->push_back(new CContact(uIDResult, uIPResult, uUDPPortResult, uTCPPortResult, uTarget, 0));
CSearchManager::ProcessResponse(uTarget, uIP, uUDPPort, pResults);
其中第一个函数是在判断自己在防火墙或者NAT之后重新发送本地节点信息的函数,包括重新得到的IP地址以及端口。
第二和第三个函数用来添加此节点作为联系人之一。
第三个函数是将此消息转入到CSearchManager中相应处理响应的函数进行处理。
void CSearchManager::ProcessResponse(const CUInt128 &uTarget, uint32 uFromIP, uint16 uFromPort, ContactList *plistResults)
{
pSearch->ProcessResponse(uFromIP, uFromPort, plistResults);// pSearch是 CSearch类的指针
}
进一步转入到pSearch->ProcessResponse(uFromIP, uFromPort, plistResults)中执行。
void CSearch::ProcessResponse(uint32 uFromIP, uint16 uFromPort, ContactList *plistResults)
{
// Not interested in responses for FIND_NODE.
// Once we get a results we stop the search.
// These contacts are added to contacts by UDPListener.
if (m_uType == NODE)
{
// Note we got an answer
m_uAnswers++;
// We clear the possible list to force the search to stop.
// We do this so the user has time to visually see the results.
m_mapPossible.clear();
delete plistResults;
// Update search on the GUI.
//IMPREVIEW theApp.emuledlg->kademliawnd->searchList->SearchRef(this);
return;
}
}
在这个函数内部我们将响应的节点数目增加一。
后面陆续接收到的消息处理流程与上述情形相似,只是对于不同的消息采取的响应以及动作并不相同。
emule中节点加入Kad网络过程(源代码详解)相关推荐
- emule中节点加入Kad网络过程(源代码详解)【对原文部分改进】
from: http://blog.csdn.net/chenbuaa/article/details/2301656 emule中节点加入Kad网络过程(源代码详解) 程序启动: EmuleDlg. ...
- android 请求方式有哪些,Android中的几种网络请求方式详解
Android应用经常会和服务器端交互,这就需要手机客户端发送网络请求,下面整理四种常用网络请求方式. java.net包中的HttpURLConnection类 Get方式: // Get方式请求 ...
- 5GC中网络切片NSSAI详解
5GC中网络切片NSSAI详解 对应5G无线网络来说,网络切片主要体现在接纳控制.网络选择和资源分离.标准主要是通过S-NSSAI (Single Network Slice Selection As ...
- 【Big Data - Hadoop - MapReduce】通过腾讯shuffle部署对shuffle过程进行详解
摘要: 通过腾讯shuffle部署对shuffle过程进行详解 摘要:腾讯分布式数据仓库基于开源软件Hadoop和Hive进行构建,TDW计算引擎包括两部分:MapReduce和Spark,两者内部都 ...
- 轻量级网络之mobilenet_v1详解
轻量级网络之mobilenet_v1详解 前言:学习网络结构有一段时间了,记录下mobilenet_v1的结构 论文地址:https://arxiv.org/pdf/1704.04861.pdf 一. ...
- P2P 中的 NAT 穿越(打洞)方案详解
P2P 中的 NAT 穿越(打洞)方案详解 转载自 : P2P 中的 NAT 穿越(打洞)方案详解 内容概述 P2P 即点对点通信,或称为对等联网,与传统的服务器客户端模式(如下图"P2P ...
- 【C++】C++中的头文件(.h)—详解(1)
[fishing-pan:https://blog.csdn.net/u013921430转载请注明出处] 前言 之前写过一篇<C++中头文件的使用>,那篇文章主要讲述C++中头文件的使用 ...
- python中类的构成_Python中类型关系和继承关系实例详解
本文详细介绍了Python中类型关系和继承关系.分享给大家供大家参考.具体分析如下: 如果一个对象A持有另一个对象B的ID,那么检索到A之后就可以检索到B,我们就说存在一个A到B的导航.这种导航关系使 ...
- python中append函数解析_对python中的pop函数和append函数详解
对python中的pop函数和append函数详解 pop()函数 1.描述 pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值. 语法 pop()方法语法: list. ...
- Incremental-Network-Quantization增量网络量化论文详解
Incremental-Network-Quantization增量网络量化论文详解 笔者将从以下几个方面分析该论文的原理及其实现,由于笔者能力有限,如有错误望诸公指正. 论文作者代码:https:/ ...
最新文章
- 系统芯片(SOC)架构- Aviral Mittal
- 《数据竞赛白皮书》发布:竞赛核心价值及促进人才数字化转型
- 【全文搜索引擎】Elasticsearch相关介绍与linux系统安装
- 十万腾讯人,自救1000天
- 朱棣文在哈佛大学毕业典礼上的演讲
- 网页登陆验证之图片验证码
- java main test_java调用main自动执行testng方法一
- Oracle分析函数-keep(dense_rank first/last)
- 启动Eclipse时发生An internal error occurred during: Initializing Java Tooling错误,详细提示如下:...
- 如何查找不包含给定字符串模式的文件?
- 如何在没有电脑的情#况下用安卓手机制作windows pe启动盘
- 移动应用开发之相关需求文档详细说明
- 人工免疫算法与物流中心选址问题
- 计算机软硬件故障排除知识,计算机软硬件基础知识及常见故障排除方法
- 最大流最小割经典例题_图割-最大流最小切割的最直白解读
- azw3转换为pdf_PDF怎么转换为PPT?PDF秒转PPT秘技!
- Python给照片换底色,基于opencv模块
- Titanic第二章:第一节数据清洗及特征处理
- win10 windows文件查找通配符
- 国际上公认的IT证书
热门文章
- Word文档的两种密码忘记了,怎么办?
- 联想g400从u盘启动计算机,【联想G40怎么从U盘启动】联想g40怎么设置u启动_联想g40从u盘启动...
- 骑士cms最新全局SQL注入(官方奇葩修复案例)
- 附件无法上传怎么办?
- 服务器显示board板,IBM x3650M4面板Board亮黄灯 故障维修
- c语言实现snn算法,Orkiszewski算法的C语言实现
- Android笔记:使用Glide加载图片刷新时会闪烁
- HDU 4234 Moving Points
- UG二次开发(C#)—依据特征获取选择体对象
- Python利用 Anaconda安装pytorch并测试GPU