⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emule源代码学习心得.txt

📁 自己收集网上牛人写的emule源码阅读经验
💻 TXT
📖 第 1 页 / 共 5 页
字号:

10. eMule源代码学习心得(10):服务器信息集-CServerList
嗯,明天要回北京了,今天打算好好休息一下,故挑了个内容少的来说,呵呵。

尽管目前有了Kad网络,但是使用服务器来获取各个emule用户的共享文件列表仍然是emule中主要的资源获取方式。CServerList就是emule中负责管理服务器列表的类。和前面若干列表类结构类似,CServerList需要对外提供列表的增加,删除,查找,修改等接口。在CServerList中,每个服务器的信息是一个CServer类。和搜索信息不一样,但是和已知文件列表一样,服务器的信息列表是需要长期保留的,因此CServerList和CKnownFileList类一样提供了把它所包含的所有信息保存到一个文件中,以及从这个文件中读回其信息的功能。

CServer中的结构比较简单,只需要保留服务器的各种信息即可。它可以通过IP地址和端口来创建,也可以通过一个简单的结构ServerMet_Struct来创建,其中后者是用来直接从文件中读取的。该结构仅仅包含IP地址和端口以及属性的个数,CServer中其它的属性在保存到文件中时,均采用Tag方式保存。

CServerList除了提供通常的CServer信息外,还提供一些统计信息诸如所有的服务器的用户数,共享的文件数等。这些统计信息也是基于每个单独的CServer的相关信息计算出来的。


11. eMule源代码学习心得(11):emule的通信协议-一些基本的约定
接下来将不可避免得要碰到emule的协议。emule的通信协议格式设计成一种便于扩充的格式。对于TCP连接来说,连接中的数据流都能够划分成为一个一个的Packet,CEMSocket类中就完成了把接收到的数据划分成Packet这一工作。但是具体的对于每个Packet进行处理的工作被转移到它的子类中进行。CEMSocket类的两个子类CServerSocket和CClientReqSocket所代表的TCP连接就分别是客户端和服务器之间的TCP连接以及客户端之间的TCP连接。在数据流中的第一个字节代表的是通信的协议簇代码,如0xE3为标准的edonkey协议,0xE4为kademlia协议等等。接下来的四个字节代表包内容的长度,所有的包都用这种方式发送到TCP流中,就可以区分出来了。另外每个包内容中的第一个字节为opcode,即在确定了某个具体协议后,这个opcode确定了这个包的具体含义。


对于走UDP协议的包,处理起来更加得简单,因为UDP本来就是以一个包一个包作为单位在网络上流传的,因此不需要在包的内容中再包含表示长度的字段。每个UDP包的第一个字节是协议簇代码,其它内容就是包的内容。CClientUDPSocket类负责处理客户端和客户端之间的UDP包,而CUDPSocket类负责处理客户端和服务器之间的UDP包。另外还有个Kademlia::CKademliaUDPListener类,专门处理和Kademlia协议相关的UDP包。

最后说一下Packet类,这个类以前只是提到过。它是emule的通信协议的最小单位。我们可以看出,它的构造函数有多个版本,这也是为了可以用不同的方式来创建Packet。例如只包含一个头部信息的缓冲区,或者只是指定协议簇代码等。而且它内部实现了压缩和解压的方法,该方法直接调用zlib库中的压缩方法,可以减少数据的传输量。这里要注意一点的就是压缩的时候协议簇代码是不参与压缩的,压缩完毕后会更换协议簇代码,例如代码为标准edonkey协议0xE3的包在压缩后,协议代码就变成0xD4了,这里进行协议代码变化是为了使接受方能够正确识别并且进行相应的解压操作。

12. eMule源代码学习心得(12):emule的通信协议-客户端和服务器之间的通信概述
客户端和服务器之间的所有通信由类CServerConnect掌握。CServerConnect本身不是套接字的子类,但是它的成员变量CServerSocket类型的connectedsocket是。CServerConnect内部有一列表,可以保存若干CServerSocket类型的指针。但是这并不说明它平时连接到很多服务器上。它只是可以同时试图连接到若干个服务器上,这只是因为连接到服务器上的行为不一定能成功。

CServerSocket类是CEMSocket的子类,它比CEMSocket要多保存一些状态,比如当前的服务器连接状态。它同时还保留它当前所连接的服务器的信息。通过分析CServerSocket::ProcessPacket就可以直接把emule客户端和服务器之间的通信协议理解清楚,这里是服务器发回的包。TCP连接建立后的第一个包是在CServerConnect::ConnectionEstablished中发出的,即向服务器发出登陆信息。如果登陆成功,则能够从服务器处获取自己的ID,这是一个32位的长整数。如果这个数小于16777216,那么我们称它为LowID。具有LowID的客户端通常情况下其它客户端将不能直接连接它。得到LowID的原因比较多,例如当自己处于NAT的后端的时候。获取自己的ID后将会向服务器发送自己的共享文件列表,这一动作由共享文件列表类CSharedFileList来完成。

其它类型包没有必要全部都列出来,以后可以通过在分析其它部分时,因为牵涉到往服务器发送或者接受数据的时候再进行相应的分析。  

13. eMule源代码学习心得(13):emule的通信协议-客户端和客户端之间的通信概述
客户端和客户端之间的TCP通信由CListenSocket和CClientReqSocket完成。这也是提供网络服务的应用程序的典型写法。其中CListenSocket只是CAsyncSocketEx的子类,只负责监听某个TCP端口。它只是内部有一个CClientReqSocket类的列表。而CClientReqSocket是CEMSocket的子类,因此它能够自动完成emule的packet识别工作。它有ProcessPacket和ProcessExtPacket来处理客户端和客户端之间的包,其中前者是经典的eDonkey协议的包,后者是emule扩展协议的包。

CListenSocket和CClientReqSocket类之间的关系和前面分析的列表类和它对应的成员类的关系是相似的,CListenSocket提供对自身的CClientReqSocket列表中的元素的增加,查询,删除等操作。同时也维护关于这些成员的一些统计信息。我们注意到CListenSocket在其构造函数中就把自己添加到CListenSocket类(theApp.listensocket,该类的唯一实际示例)的列表中。

CClientReqSocket类和CUpDownClient类之间存在着对应关系。它们都表示了另外一个客户端的一些信息,但是CClientReqSocket类主要侧重在网络数据方面,即负责两边的互相通信,而CUpDownClient类负责的是从逻辑上对网络另一边的一个客户端进行表达。CUpDownClient类代码很长,以后再说。  

14. eMule源代码学习心得(14):emule中的信誉机制
信誉机制在P2P系统中有非常重要的作用。为了使用户更加愿意共享自己的资源,需要有一些机制能够让对整个P2P系统贡献更大的用户有更多的激励。在emule中,激励机制的设计方案是tit-for-tat这种最直观的方案。这种方案的意义就是最简单的如果别人对你好,那么你也对别人好。

下面看实际的实现。CClientCreditsList和CClientCredits类负责emule中的信誉机制。我们再次见到这种列表和元素之间的关系,不必再重复那些语言。和信誉相关的信息是需要永久保存的,这样才有意义,因此CClientCreditsList提供了LoadList和SaveList方法。我们另外注意到,CClientCredits类可以使用CreditStruct结构来创建,而CreditStruct结构只包含静态信息。主要是上传量和下载量等。

信誉机制的信息需要有一定的可靠性,在emule中采用了数字签名的方式来做到这一点。Crypto++库为emule全程提供和数字签名验证相关的功能。CClientCreditsList在创建时,会装载自己的公钥私钥,如果没有的话,会创建一对。CClientCreditsList中包含的有效的信息都是经过其它人数字签名的,所以更加有信服力。在实际使用中,这些信息和自己的私钥要注意保存。重装emule后应该把配置文件目录先备份,这样能够保留自己辛辛苦苦积攒的信誉。  

15. eMule源代码学习心得(15):下载任务即部分文件的表示
CPartFile类是emule中用来表示一个下载任务的类。从它的名字也可以看出来,这就是一个还没有完成的文件。当一个下载任务被创建时,emule会在下载目录中创建两个文件,以三位数字加后缀part的文件,例如001.part,002.part等。还有一个以同样的数字加上.part.met的文件,表示的是对应文件的元信息。part文件会创建得和原始文件大小一样,当下载完成后,文件名会修改成它本来的名称。而事实上,诸如这个文件原来叫什么名称,修改日期等等信息都在对应的.part.met元文件中。.part.met中还包含了该文件中那些部分已经下载完成的信息。

CPartFile类中Gap_Struct来表示文件的下载情况,一个Gap_Struct就是一个坑,它表示该文件从多少字节的偏移到多少字节偏移是一个坑。下载的过程就是一个不断填坑的过程。CPartFile类中有个成员变量gaplist就是该文件目前的坑的状况列表。需要主要的是有时填了坑的中间部分后,会把一个坑变成两个坑。坑的列表也会被存进.part.met中。

CPartFile类的代码很庞大,但是这是必须的。首先,它的创建就有几种可能,从搜索文件CSearchFile中创建,这种情况发生在用户搜索到他想要的文件后点击下载时发生。从一个包含了ed2k链接的字符串中创建,它会提取出该ed2k链接中的信息,并用来创建CPartFile。剩下的一种,就是当emule程序重启后,恢复以前的下载任务。这时就是去下载目录中寻找那些.part和.met文件了。另外它还需要不断得处理下载到的数据,为了减少磁盘开销,使用了Requested_Block_Struct结构来暂存写入的数据。它内部维护一个CUpDownClient的列表,如果知道了该文件的一个新的来源信息,就会创建一个对应的CUpDownClient。后者是emule中代码量最大的类。它还要把它的状态用彩色的条装物显示出来提供给GUI。

前面提到的AICH机制对于最大程度得保证下载文件的正确性以及尽量减少重复传输都有很大的帮助,在下载的过程中,该机制会经常对下载到的数据进行校验。

最后提一下它的Process方法。该方法是emule中为了尽量减少线程的使用而采取的一种有一些类似于轮询的机制。其它很多类中也有Process方法,这个方法要做的事情就是在一些和日常运行有关的事情,例如检查为了下载该文件而链接到自己的各个客户端的状态,向它们发送下载请求等。

16. eMule源代码学习心得(16):下载任务队列
CDownloadQueue是下载队列类。这个队列中的项目是CPartFile指针。因此和emule中出现的很多其它的列表类一样,它需要能够提供对这个列表中的元素进行增加,查询,删除的功能。例如查询的时候能够根据该文件的hashID或者索引来进行查询。CDownloadQueue同时还要完成一些统计工作。

和其它的列表类不一样的是,它的所有元素的信息并不是集中存放于一个文件,而是对应于每一个下载任务,单独得存放在一个元信息文件(.part.met)中,因此当该类进行初始化的时候,它需要寻找所有可能的下载路径,从那些路径中找到所有的.part.met文件,并且试图用这些文件来生成CPartFile类,并且将这些通过.part.met文件正确生成的CPartFile类添加到自己的列表中,同样,在退出时,所有的下载任务的元信息也是自行保存,不会合成为一个文件。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -