eMule源码主要调用流程分析
站长推荐:NSetup一键部署软件
一键式完成美化安装包制作,自动增量升级,数据统计,数字签名。应对各种复杂场景,脚本模块化拆分,常规复杂的脚本代码,图形化设置。无需专业的研发经验,轻松完成项目部署。(www.nsetup.cn)
从事P2P下载开发的原因,仔细分析了eMule下载的协议和实现的技术细节,下面是对eMule源代码下载流程的简要分析:
主体结构:(按照下面的调用顺序启动主要流程) 1.Emule对话框类CEmuleDlg::OnInitDlg ::SetTimer(NULL, NULL, 300, StartupTimer) 设置启动定时器;
2. 定时器函数void CALLBACK CemuleDlg::StartupTimer(。。)完成各对象初始化初始化服务器列表
3. theApp.serverlist->Init();从文件中读取 struct ServerMet_Struct { uint32 ip; uint16 port; uint32
tagcount;}+tag ( 标签)和从文本文件读取静态server列表;
4. 下载队列初始化 theApp.downloadqueue->Init();
5. 启动客户端监听 theApp.listensocket->StartListening()CClientUDPSocket对象创建套接字theApp.clientudp-
>Create()
6.检测启动是否自动连接服务器if (thePrefs.DoAutoConnect())连接emule服务器 theApp.emuledlg-
>OnBnClickedButton2();
7. 调用connectserver对象的trytoconnectanyserver()连接全局服务器。
下载文件的流程:
详细见类CServerConnect的分析从下载搜索结果中选择下载一个文件程序调用流程:
1。CSearchResultsWnd::OnBnClickedDownloadSelected()–>CSearchResultsWnd::DownloadSelected(bool bPaused –
>theApp.downloadqueue->AddSearchToDownload(&tempFile, bPaused, m_cattabs.GetCurSel());–〉
CDownloadQueue::AddDownload()加入下载队列尾部。
2。 开始下载在由static VOID CALLBACK CUploadQueue::UploadTime 定时器函数处{..theApp.downloadqueue->Process
();..}CUploadQueue::CUploadQueue() //构造函数设的 的 置定时器100毫秒 { VERIFY( (h_timer = SetTimer
(0,0,100,UploadTimer)) != NULL );。….} 下载在CDownloadQueue::Process()处理–> CPartFile::Process()–
>CUpDownClient::AskForDownload{ SetDownloadState(DS_CONNECTING); return TryToConnect();…}
3。进入 CUpDownClient ::TryToConnect(){ 建立客户端请求socket对象并创建socket CClientReqSocket * socket =
static_cast(pClassSocket->CreateObject()); socket->SetClient(this); if (!socket->Create())如果该客户端是lowid
发送callback请求否则调用CUpDownClient::Connect()和该源客户端发起tcp连接请求由socket->Connect完成然后发送握手请求
op_hello;
4。接下来CClientReqSocket 类ProcessPacket中进行等待处理 OP_HELLOANSWER在 case OP_HELLOANSWER: { client
->ProcessHelloAnswer(packet,size); if (client) { client->ConnectionEstablished() }–
>CUpDownClient::ConnectionEstablished() {switch(GetDownloadState()) { case DS_CONNECTING: CUpDownClient::
SendFileRequest()…负责发出文件下载相关请求的操作 OP_MULTIPACKET 将多个消息打包作为一个新消息发送支持
WritePartStatus 文件状态的表示 每个部分用一个二进制位表示,完成为1否则为0 }
5。 接下来发出OP_STARTUPLOADREQ请求,CUpDownClient::SendStartupLoadReq()请求开始下载文件(如果有其他客户端在下
载同一个文件,那么下载客户端将被放入上传队列中连接断开。) (当下载客户端到达上传客户端上传队列顶部时如果
连接已断开,上传客户端连接下载客户端,如果连接已断开连接建立后发送
OP_ACCEPTUPLOADREQCUploadQueue::AddUpNextClient(LPCTSTR pszReason, CUpDownClient* directadd)第一个参数说明了每次
调用该函数增加客户端上传的原因(即从上传等待队列放入正在上传的队列。// tell the client that we are now ready to
upload if (!newclient->socket || !newclient->socket->IsConnected()) { if (!newclient->TryToConnect(true))
} else { Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);}void CUploadQueue::Process() 每100毫秒调用一次 if
(ForceNewClient()){AddUpNextClient(_T(“Not enough open upload slots for current ul speed”));}cur_client-
>SendBlockData();
6. 发送peer请求的数据块CUpDownClient::ConnectionEstablished() case US_CONNECTING: case
US_WAITCALLBACK: if (theApp.uploadqueue->IsDownloading(this)) { SetUploadState(US_UPLOADING);
Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0); socket->SendPacket(packet,true); })文件正式开始下
载是接收到OP_ACCEPTUPLOADREQ消息开始,case OP_ACCEPTUPLOADREQ:client->ProcessAcceptUpload
();CUpDownClient::ProcessAcceptUpload()–>CUpDownClient::StartDownload()–>CUpDownClient::SendBlockRequests()
网络层相关类:
class CEMSocketvirtual bool PacketReceived(Packet* packet) = 0; protected处理接收到的网络数据包,被定义为纯虚函
数,各网络相关类由lass CEMSocket派生,各自对收到的包的处理不同。该函数在OnReceive中被调用OnReceive同样为虚函数
class CListenSocket 负责每个客户端监听一个tcp端口,每接受一个其他客户端tcp连接就创建一个CClientReqSocket对象,来
处理对应的客户端发送的相关消息。CUpDownClient 试图连接其他客户端的时候也会创建一个CClientReqSocket的对象以连接到
其他peerCEMSocket::OnSend(int nErrorCode){;if(m_currentPacket_is_controlpacket) { // queue up for
control packet theApp.uploadBandwidthThrottler->QueueForSendingControlPacket(this, HasSent()); }
发送的数据报分两种受控和标准, 受控数据报优先级较高Sendpacket() 将数据报推向受控队列,并且相关soket对象指针加入流
量控制对象中,最终由流量控制类通过指针调用socket对象的send函数发送网络数据, if (controlpacket) {
controlpacket_queue.AddTail(packet); // queue up for controlpacket
theApp.uploadBandwidthThrottler->QueueForSendingControlPacket(this, HasSent());
标准数据报被推往标准队列中CserverConnect类主要功能,维护和文件服务器的联接。
流量控制相关类UploadBandwidthThrottler uploadBandwidthThrottler 全局有一个该对象,发送的数据报
UploadBandwidthThrottler类对象在 CemuleApp::InitInstance()种建立uploadBandwidthThrottler = new
UploadBandwidthThrottler();在构造函数中启动数据报发送控制的线程AfxBeginThread(RunProc, (LPVOIDthis);
UploadBandwidthThrottler::RunInternal(){socket->SendControlData( 发送送控数据包socket-
>SendFileAndControlData(发送标准数据包CClientReqSocket 负责建立和其他客户端的tcp连接 ,监听其他客户端请求消息
和处理 协议消息,该类支持动态创建CUpDownClient 对应没个上传下载的客户端启动文件hash线程start aichsyncthread
AfxBeginThread(RUNTIME_CLASS(CAICHSyncThread), THREAD_PRIORITY_BELOW_NORMAL,0);
关于eMule的源码分析和协议分析细节可以参考我翻译的文档和撰写的源码分析报告诉。文档下载地址:http://hi.csdn.net/ganghust/profile,我的个人空间的资源部分。
学习日记,兼职软件设计,软件修改,毕业设计。
本文出自 学习日记,转载时请注明出处及相应链接。
本文永久链接: https://www.softwareace.cn/?p=429