译自 Yoram Kulbak and Danny Bickson 《The eMule Protocol Specification》
翻译:lzcx
QQ:402722857
EMail: lzcx_cn@yahoo.com.cn
供学习用,转载请注明出处
4
客户端到客户端的
TCP
交流
在eMule客户端注册到服务器和向服务器查询文件和源之后,为了下载文件,eMule客户端需要联系其它客户端。为每对[文件,客户端]创建一个专用的TCP连接。当特定的周期内(默认40秒)没有任何socket活动或者对方已经关闭了这个连接,那么这个连接就会关闭。
为了提供合理的下载速率,直到可能提供给它(和所有其它下载的客户端)至少最小允许速率(当前的硬编码常量设置为2.4k/s),eMule才允许客户端开始下载文件。
4.1
初始的握手
初始的握手是对称的 - 双方都相互发送相同的信息给对方。客户端交换双方的信息,信息包括身份认证、版本和容量等。参与的有两种类型消息 - Hello消息(6.4.1节)和eMule信息消息(6.5.1节),第一种是eDonkey的一部分,兼容eDonkey客户端,第二种是eMule独有的扩展客户端协议的一部分。图4.1图解了两个eMule客户端之间的握手。在扩展信息中包含的有UDP消息交换、安全身份证明和源交换能力。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-1.jpg)
4.2
安全的用户身份认证
1.4节简单解释了关于用户ID和用户假冒其它用户的动机。安全用户认证是eMule扩展的一部分。如果客户端支持安全认证,就会在初始化握手之后立即执行。安全认证的目的是防止用户冒名顶替。当实施安全认证时,执行以下步骤:
1.在初始化握手中,B客户端指明它支持和希望使用安全认证。
2.通过发送安全认证消息(见6.5.8)来回应,指明A是否需要B的公匙,也包含了B发出的4字节的询问。
3.如果A指明它需要B的公匙,B就将它的公匙发送给A(6.5.9节)。
4.B发送一个签名消息(6.5.10节),签名消息是用发送过来的询问和额外的双字节创建的,双字节要么是A的IP地址如果B是低ID,要么是B的ID如果它有高ID。图4.2演示了这个顺序。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-2.jpg)
4.2.1
信用系统
本节简要地描述了客户端的信用系统。信用系统的目的是鼓励用户共享文件。当客户端上传文件给它的对方,下载的客户端就根据数据传输的数量来更新它的信用。注意,信用系统不是全局的 - 传输的信用被下载的客户端局部保存,只有当上传的客户端(获得信用的那个)要求从这个特定的客户端下载时,信用才会被考虑。信用是用下面最小值计算的:
1. 上传的总量 * 2 / 下载的总量
当下载的总量是零时,这个表达式估值是10
2. 上传的总量 + 2 的和开方
当上传的总量小于1MB,这个表达式估值是1
上传/下载数量是以M为单位计算。任何情况下,信用不会高过10或者低于1。
4.3
请求文件
正如已经提到的一样,每对[客户端,文件]都创建一个独立的连接。在连接建立之后,客户端立即发送几个关于它希望下载的文件的请求消息。4.3节描述了一个典型的、成功的情景。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-3.jpg)
4.3.1
基本消息交换
基本消息交换是由四个消息构成:A发送一个文件请求消息,立即跟着的是请求文件ID消息(6.4.17节)。B用文件请求回答回应文件请求,用文件状态(6.4.18节)来回应请求文件的ID消息。我找不到任何理由来把这些发送过来的消息中的信息分成四个消息,它可以容易地用两个消息(请求和回应)来处理。
扩展协议增加两个消息到这个顺序中,源请求消息(6.5.6节)和源回应消息(6.5.7节)。用这个扩展来传递B的源(假定B当前下载着文件)到A中。详细阐述就是,在它能发送文件块给其它客户端之前B完成下载一个文件是没有任何要求的,B可以发送任何它已经完成下载的文件块,甚至当它只是用文件的一小块。
4.3.2
没找到文件的情景
当A向B请求一个文件,但是B的共享文件列表中没有这个文件。B忽略这个文件请求回应消息,在请求文件ID消息之后立即发送一个没有文件消息(6.4.16节),如图4.4所演示。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-4.jpg)
4.3.3
加入上传队列
当B有被请求的文件但是它上传队列不为空,意味着有正在下载文件的客户端,也可能有客户端在上传列表中,在这种情况下,A和B执行满握手,如图4.3所述,但是当A请求B开始下载文件时,B把A加入到它的上传队列中,回应一个队列等级消息,这个消息包含A在B地上传队列中的位置。图4.5演示了这个顺序。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-5.jpg)
4.3.4
上传对列管理
对每个上传的文件,客户端维护着一个上传优先级队列。队列中的每个客户端的优先级是以客户端在队列中的时间和优先级修正为基础计算的。位于队列头部的客户端有一个最高级别的分数。分数是用以下的方程式计算的:分数 = (等级 * 队列中的秒数)/100或者无穷大,如果下载的客户端被定义为朋友。初始化的等级值是100,除开禁止的用户是0等级(这样阻止达到队列的前面)外。等级可以被下载客户端的信用(范围1-10)或上传文件优先级(0.2-1.8)修改,上传文件优先级是由上传客户端设置的。当一个客户端的分数比其它的客户端高时,它就开始下载文件。客户端可以继续下载文件直到产生以下任一个条件:
1.用户关闭了上传客户端。
2.下载的客户端得到了它所需文件的所有部分。
3.下载的客户端给其它拥有比它更高优先级的客户端抢占。
为了允许一个刚刚开始的客户端在它被抢占之前可以得到几M的数据,eMule在客户端下载的前15钟内增加初始等级到200。
4.3.5
到达上传队列的顶部
当A到达B上传队列的顶部时,B连接A,执行初始握手,然后发送一个接收上传请求消息(6.4.11节)。A现在可以选择要么发送请求块消息来继续下载文件,要么发送取消传输消息来取消(如果它已经从别的源得到了这一块)。图4.6演示了这些选择。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-6.jpg)
4.4
数据传输
4.4.1
数据包
发送和接收文件块是eMule网络活动的主要部分。用FTP解释eMule可以推论出,当所有其它eMule可以控制,发送的文件块适合数据传输。发送的文件块大小可以是在5000到15000位(也根据压缩)范围内。为了避免出错,文件块消息在碎片中发送,每碎片在一个独立的TCP包中。在eMule 0.30e版中,最大的碎片大小是1300位(注意,这个数字只与TCP有效负载有关)。换句话说,当每个控制消息在单独的TCP包中发送,有时和其它消息共享,数据消息被分成几个TCP包。第一个包包含发送文件块消息头部(6.4.3节)。剩下的包值包含数据。当被分成1300,如果发送块的大小有剩余,和第一个包(这个包带有头部)一起发送。图4.7演示了文件块消息。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-7.jpg)
4.4.2
数据传输顺序
在文件请求回应之后立即开始块传输顺序。下载客户端A发送一个开始上传请求(6.4.10节),然后一个接收上传请求消息(6.4.11节)回应这个请求。A在这之后立即开始请求文件块(6.4.4节),B通过发送被请求块(6.4.3节)来回应。注意,单独的文件块请求可能请求可达3块之多,所以每个文件块请求可能被可达3个发送的块顺序回应。
当两个客户端都支持扩展的客户端协议,文件块可能压缩发送。扩展协议也支持可选的文件信息消息(6.5.5节),该消息就在接收上传请求消息之前发送。图4.8演示了块传输消息顺序。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-8.jpg)
4.4.3
选择块下载
为了最大化整个网络的吞吐量和共享,eMule仔细挑选选择块的下载顺序。每个文件被分成9.28M的块,每部分分成180KB的片。
块下载的顺序是由发送请求文件块消息(6.4.4节)的下载客户端决定。下载客户端可以在任何给定时刻从各个源中下载一个单独的文件块,所有从相同源中请求的片都在同一个块中。下面的原理(以这个顺序)应用于下载块等级:
1.(可获得的)大片的频率,尽可能快的下载非常稀少的大片来形成一个新的源。
2.用来预览的块(最初+最后的大片),预览或检查文件(比如,电影、mp3)
3.请求状态(过程中下载),尝试向每个源询问其它的大片。在所有源之间扩散请求。
4.完成(未到某种程度的完成),在开始下载另一个时应该完成获得部分的大片
频率标准定义了三个区域:非常稀少、稀少和一般。在每个区域里,标准有特定的权重,用来计算块等级。较低等级的块先下载。下面的列表根据上面的原理指定文件等级范围:
l
0-9999 - 不请求和请求非常稀少的块
l
10000-19999 - 不请求稀少和预览块
l
20000-29999 - 不请求大部分完成的一般的块
l
30000-39999 - 请求的稀少和预览的块
l
40000-49999 - 请求的没有完成的一般的块
这个算法通常选择第一个最稀少的块。然而,部分完成的块,接近完成的,也可能被选中。对于一般的块,在不同的源之间扩散下载。
4.5
浏览共享的文件和文件夹
有两个消息流程来处理每对客户端之间的共享文件和文件夹的浏览。第一个是浏览共享文件消息(6.4.21节),该消息在初始握手后立即发送。通常由一个浏览共享文件回应消息(6.4.22)来回应这个消息。当回应的客户端想隐藏它的共享文件列表时,回应就包含零个文件(而不是发送一个指示访问拒绝的消息)。图4.9演示了这个消息顺序。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-9.jpg)
第二个消息流程随着一个浏览共享的文件夹列(6.4.23节)表请求开始,通过共享文件夹列表来回应这个消息,然后,对于回应中的每个文件夹,发送浏览共享文件夹内容的消息。当消息到达时,回应的每个消息带有内容列表。图4.10演示了这个消息顺序。
如果接收的客户端设置了阻塞共享文件/文件夹请求,它用请求共享拒绝消息回应,如图4.11所示。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-1011.jpg)
4.6
交换片哈希集
为了取得片的哈希,发送一个哈希集请求,这个请求通过一个包含文件中每块的哈希集回应来回答。图4.12演示了这个。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-12.jpg)
4.7
取得文件预览
客户端可以请求对方来获得下载文件的预览。预览是种独立的、随着文件类型不同而不同的应用。eMule 0.30e只支持图像预览。这个消息交换如图4.13描述,只包含两种消息:预览请求(6.5.11节)和预览回应(6.5.12节)。
![](http://blog.csdn.net/images/blog_csdn_net/lzcx/4-13.jpg)
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=612414