-
最主要的参考文本是
eMule
协议
1.0
版,
原文地址
。<
/p>
分析的流程是简要翻译加上我的思考,
我的目标不在
于完整的翻译,想看完整翻译的可以关注下
p2p
分
发引擎研究
这个
Blog
,他正在
p>
翻译协议文本
。我的思
考和点评会用红色标
出。
--------
电骡
eMule
是基于电驴
eDonkey
协议的。
电骡网络是由数百个电骡服务器和
数百万的电骡客户端组成的。
客户端必须连接到服务器来获得网络服务,这个连接要一直
保持直到客户端关闭。服务器提供集中的索引
服务(类同
Nap
ster
)
,不同的服务器之间没有通讯。
每个电骡客户端都预先设置好了一个服务器列表和一个
本地共享文件列表。
客户端通过一个单一的
TCP
连
接到电骡服务器进行网络登陆,
得到想要的文件的
信息和可用客户端的信息。
(
这样造成了电骡和电驴都不
能完全去中心化,虽然文件存储在客户端上。
)电骡客户端用几百个<
/p>
TCP
连接与其他的客户端连接进行文
件
的上传和下载。每个电骡客户端为它的共享文件维护一个上传队列。正在下载的客户端加入这个队列的
底部,然后逐渐的前进,直到他们达到队列的顶端开始下载文件。一个客户端可能从多个其他的电骡 客户
端下载同一个文件,从不同的客户端取得不同的部分。客户端也可以上传一个没有完
全下载的文件的部分
数据。
(
文件可以
分块传输大大提高了效率,但是也造成了一些问题,比如源提前退出以后,所有的客户端
都是不完全数据的情况。
)
最终,
电骡
扩展了电驴的能力允许客户端交换关于服务器、其他客户端和文件的
信息。
(
这个能力又开始把中心的意义淡化。
)注意,客户
端和服务器的通信都是基于
TCP
的。
服务器使用一个内部数据库来保存客户端和文件的信息。电骡
服务器不保存任何文件,它是文件位置信息
的中心索引。服务器的另一个功能,正在受到
质疑,他将作为通过防火墙连接的客户端之间的桥梁,这样
的客户端不能接受引入的连接
。
桥接功能大大的增加了服务器的负载。
(
这个功能让服务器承担了过分的负
担,大大降低了服务器的能力,在设计中应该摒弃
,目前应用中大部分的服务器已经关闭了这个功能,也
就是说两个
Low
id
的客户端是不能传输数据的。
< br>)电骡使用
UDP
增强客户端跟服务器和其他客户端的通
信能力。但是客户端收发
UDP
信息的
能力不是客户端日常操作强制要求的,即使防火墙阻止客户端收发
UDP
信息,客户端仍能完美的工作。
客户端到服务器的连接
图一
电骡网络图
客户端一启动就会用
TCP
连接到一个电骡服务器。
服务器给客户端提供一个客户端
ID
,
这个
ID
仅在客户
端服
务器连接的生命周期内有效
(注意如果客户端是高
ID
,
那么他在所有的服务器得到的
ID
都是一样的,
直到他的
IP
地址变化为止)
。连接建立后,客户端把它共享的文件列表
发送给服务器。服务器把这个列表
保存在它的内部数据库内,这个数据库通常包括了数十
万可用文件和活动客户端。电骡客户端也会发送它
的下载列表,包含了他想要下载的文件
。后面将给出电骡客户端和服务器间的
TCP
信息交换格式细节
。
连接建立以后,
电骡服务器给客户端发送一个列表,
这个列表包括了那些有客户端需要的文件的
客户端
(这
些客户端叫做源)
。然后,
客户端就去跟那些有所需文件的客户端建立连接。
注意客户端服务器的
TCP
连接在整个客户端会
话过程中都会保持。
初始化握手之后,
事务主要是由用户活
p>
动触发的:有时客户端发送一个文件查找请求给服务器,服务器会返回一个查找结果,一个查
找事务之后
通常是一个对指定文件的源查询,这个查询的结果是一个可以提供该文件下载
的源的列表。
电骡客户端用
UDP
来跟登录服务器以外的服务器进行通信。
UDP
信息的用途是增加文件搜索能力,源搜
索能力,保持连
接。
客户端到客户端之间的连接
电骡客户端一般是为了下载某个文件才会连接到其他的客户端
(也就是源)
的。
一个文件会被分为很多块。
< br>客户端会从多个客户端(源)那里下载同一个文件,从不同的源下载文件的不同部分(
这样不同的部分就
可以同时被下载,如果源多,下载的效率就会极高
)
。
当两个客户端连接后,他们会交换容量信息,然后协商开始下载
(
< br>或者说是上传
,
这取决于视角
)
的时间。每
个客户端有一个下载队列,
用来保存正在等待下载的客户端的列表。
当电骡客户端的下载对列为空的时候,
下载请求会被马上接受
(除非这个请求者已经被屏蔽)
< br>。如果下载对列不为空,那么新的下载请求就会放在
队列之中。
< br>不会努力服务更多的客户端,
对每个下载客户端至少保持不少于
< br>2.k
字节
/
每秒。
一个正在下载
的客户端的下载地位可能被一个对列等级(
< br>queue ranking
)比他高的等待客户端抢占,在下载进程中的
前
15
分钟正在下载的客户端的队列等级会增
长用来避免产生颠簸(
这里说的颠簸就是说,一个客户端频
繁的
从下载地位切换到等待状态,然后再切换回去。这种频繁的切换叫做颠簸,这对资源是种浪费,所以
要避免。
)
。
当正在下载的客户端到达了下载队列的顶部,提供上传的客户
端初始化一个连接用于把它需要的文件片断
传送给它。一个电骡客户端可能会在多个源客
户端的等待队列中,在每个客户端上注册要求同一个文件片
断。当这个等待客户端实际上
完成了这个文件片断的下载,他不会通知那些源客户端删除它的请求,而仅
仅是在它在那
些源客户端的队列中排到顶端的时候拒绝上传请求而已。
<
/p>
电骡使用一个声望系统来鼓励上传,为了防止假冒,电骡用
RSA
公钥加密技术来保护声望系统。
客户端连接中会使用很多电驴协议(
eDonkey
protocol
)没有定义的消息,这些消息叫做扩展协议。扩
展协议用来实现信用系统,用来进行信息交换(例如,服务器列表的更新和源的更新)
,通过对文件块进行
压缩提升发送和接收的效率。电骡客户端连接中有限
地使用
UDP
去周期其他客户端的状态。
客户端
ID
客户端是一个
4
字节的标识符,在跟服务器连接握手的时候由服务器提供的。客户端
ID
仅在客户端服务
器
TCP
连接的生命期内可用,虽然如果客户端是高
ID
(
High ID
)
< br>,它在任何服务器分配的客户端
ID
都
< br>一样,除非
IP
变化了。客户端
ID
分为低
ID
(
low ID
)和高
ID
。电骡服
务器通常会给不能接受连接的客
户端分配低
ID
。拥有低
ID
会限制客户端在电骡网络中的使用,甚至
会造成服务器拒绝连接。高
ID
是由
客
户端的
IP
地址为基础算出的。这里从电骡协议的观点来看客户
端
ID
的分配和表示。得到高
ID
p>
的客户
端允许其他的客户端自由地连接他的电骡
TCP
端口(默认为
4662
)<
/p>
。
得到高
ID
的
客户端在电骡网络内不
受任何限制。当服务器不能打开一个连往客户端的电骡端口的连接
时,服务器给客户端一个低
ID
。这主要
是客户端安装了防火墙组织外来连接造成的。以下情况下,客户端会得到低
ID
:
?
?
当客户
端通过
NAT
或者代理服务器上网。
当服务器正在忙(造成服务器的连接计数器超时,从而认为客
户端无法连接)
。
高
ID
通过下面的方法计算:假设机器
IP
地址为
X.Y
.Z.W<
/p>
,客户端
ID
应该为
X+2
8
*Y+2
16
*Z+2
24
*W
p>
(
big endian
高位在前)
。
低
ID
总是小于<
/p>
15777216(0x1000000)
我不知道它是怎么计算
的
(
协议原文
如此,看来低
ID
的算法并不重要,只要满足条件即可。
)
p>
,注意从不同的服务器得到的低
ID
是不一
样的。
低
ID
的客户端没有公开的
IP
地址供其
他的客户端连接,所以所有的通信必须通过电骡服务器。这会造成
服务器的负载提升,所
以服务器不愿意接受低
ID
的客户端。同样,这说明低
ID
的客户端不能跟其他服务
器上面的低
ID
客户端连接,因为电骡不支持服务器间的桥接。
< br>
为了支持低
ID
客户端电骡协议引入了回调机制。
使用这种机制,
一个高
ID
客户段可以要求
(通过服务
器)
低
ID
客户端连接它来交换文件。
(
现在大
部分服务器不会拒绝低
ID
的客户端连接,因为他们基本上都不
帮助客户端传输文件了。由此,
低
ID
的客户端之间也无法传输了。
)
用户
ID
电骡支持声望系统为了增加用户的文件共享。
一个用户上传给其
他客户端越多东西,
它就得到越多的声望,
这样它在他们的等待
队列中前进就会越快。用户
ID
是一个
128
位(
16
字节)
GUID
,通过连接随机数而
产生,
< br>第
6
和第
15
< br>位不是随机生成的,
他们分别是
14
和
111
。
用户
< br>ID
仅在客户端和服务器会话中有效,
用户
ID
是唯一的用来标识客户端。
用户
ID
在声望系统里面起了很大的作用,攻击者冒充其他用户就是为
了得到它们声望对应的权利。
电骡提供了加密方案用来用户欺诈。
实现方式是用
RSA
方法来加密方法来加
密信息交换。
文件
ID
文件
ID
用于网络中文件的唯一标识,
以及文件损坏的检测和修复。注意电骡对文件进行唯一标识和编目
不依赖于文件名,文件
由其内容哈希计算出来的全局唯一
ID
来标识。文件
ID
有两种,一种用来生成唯一
标识,一种用于文
件损坏的检测和修复。
文件哈希
文件是用一个
128
位的
GUID
来标识的,这
个
GUID
是由客户端用文件内容哈希计算出来的。
GUID
使
用
MD4
p>
算法计算。计算文件
ID
的时候文件被分成
9.28MB
的大小。一个
GUID
是分别计算每个文件块
的哈希,然后把
它们合成为一个唯一文件
ID
。下载客户端完成文件块的下载后
,会计算块的哈希和文件上
传端发送来的文件块哈希做比较,如果不同,就说明文件块损
坏了,客户端将逐块的覆盖(一次
180kb
)
知道哈希计算表明文件块已经修复为止。
根哈希
根哈希是每个文件块用
SHA1
算法计
算出来的,
每个计算单元尺寸为
180kb
。
它提供了更高级别的可靠性
和错误恢复。
电骡协议拓展
虽然电骡(
eMule
)完全兼容电驴(
eDonkey
)
,但是它还是实现了一些扩
展,用于增强它的功能。扩展
关注于客户端和客户端之间的通信,特别是安全领域和
p>
UDP
工具。
软件和硬件限制
< br>服务器设定包括两种对活跃用户数目的限制,软件的和硬件的。硬件限制大于等于软件限制。当活跃用户< /p>
数目到达了软件限制,服务器停止接受新的低
ID
客户端连接,当用户数目达到了硬件限制,服务器不会
接受任何连接。
2
客户
端服务器的
TCP
交流
每个客户端用
TCP
精确地连接到一个服务器。服务器分配给客户端一个
ID,
< br>在与服务器其余的会话中标识
该客户端(高
ID
客户端总是根据它的
IP
地址分配)
。
eMule GUI
客户端需要建立一个服务器
连接来用于
操作。客户端不能同时与几个服务器连接,也不能在没有用户干涉的情况下动
态更换服务器。
2.1
建立连接
在准备建立与服务器的连接时,
客户
端会尝试并行地连接到几个服务器,
根据成功的登陆顺序放弃其他的。
< br>
有下面几个可能的连接建立个案:
< br>1
、高
ID
连接
-
服务器分配一个高
ID
给正
在连接的客户端
2
、低
ID
连接
-
服务器分配一个
低
ID
给正在连接的客户端
3
、拒绝会话
-
服务器
拒绝客户端
当然,也有不重要的个案
-
服务器崩溃或者不可连接。
p>
图
2.1
描述了导致高
ID
连接的信息顺序。在这种情况下,客户端建立一个
TC
P
连接到服务器,然后发送
一个登录信息到服务器。服务器用另
一个
TCP
连接到客户端,执行一个客户端
-
客户端的握手来保证连接
的客户端有能力接收来自其他<
/p>
eMule
客户端的连接。在完成客户端握手后,服务器关闭第二
个连接,通过
发送
ID
更改信息来完成
客户端
-
服务器的握手。
你可能注意到
eMule
信息消息是灰色的。
这是因
为这个消
息是
eMule
协议扩展的一
个部分(
1.6
节)
图
2.2
描
述了导致低
ID
连接的信息顺序。在这种情况下,服务器不能连
接到发送请求的客户端,分配一
个低
ID
给客户端。服务器消息一般包含警告信息,就像
“
警告
[
服务器细节
]
-
你是低
ID
。请察看你的网
络配置和
/
或你的设置
”
低
ID
和高
I
D
握手都是通过随着
ID
更改消息完成
的,这个
ID
更改消息分配客户
端一个
客户端
ID
,用在与服务器的下一个会话。
图
2.3
描述了被拒绝的会话顺序。因为客户端拥有一个低
ID
或者
到达了服务器硬件的容量限制,服务器
就可能拒绝会话。服务器消息会包含一个短字符串
描述拒绝的理由。
2.2
连接启动时消息交换
在建立成功的连接后,客户端和服务器交换几个设置消息。这些消息的目的是根据双方状态来双方更 新。
客户端通过提供它的共享文件列表(见
6.2.4
节)给服务器来开始,然后要求更新它的服务器列表。服务
器发送它的状
态和版本(
6.2.6
节和
6.2.2
节)
,然后发送它所知的
eMule<
/p>
服务器列表和提供更多一些自
我认定的细节。最后客户端要求源(
可以访问下载它下载列表中的文件的其它客户端)和服务器回应一系
列的消息,客户端下
载列表中的每个文件,直到下载所有的源列表到客户端。图
2.4
图解了这个顺序。
2.3
文件搜索
文件搜索是由用户发起的。这个操作简单,一个搜索要求(
见
6.2.9
节)发送到服务器,然后服务器用一
个搜索结果回应。当有很多结果时,搜索结果消息就会被压缩。接着,用户选择下载一个或多个文件,
客
户端就要求源为选中的文件和服务器返回每个要求文件的源队列
(见
6.2.12
节)
。
就在回应发现的源之前,
可以发送一个可选的服务器状态消息。这个状态消
息(
6.2.6
节)包含关于当前用户数量和服务器支持的
p>
文件等信息。
重要注意的是,
UDP
消息有个补充顺序事件,
用来增强客户端为它搜索的文件定位源的能力
,
详细的细节见第
3
章。在检验出源是
新的之后,
eMule
客户端开始尝试连接和把它们加入到它的
源列表。
源联系的顺序就是
eMule
客户端接收到它们的顺序。图
2.5
描述了文件搜索顺序。
p>
eMule
客
户端根据源加入到它的列表中的顺序来连接源。没有优先机制来决定连接那个源。当可以要求同
< br>一个源来下载客户端下载列表中的几个文件时,有一种复杂的机制来解决这个局面(注意,载客户端之间< /p>
eMule
只允许一个单独的上传连接)
。选择算法是基于用户优先规则,当没有指定优先时,默认是字母顺
序。关于处理可以上
传多于一个文件的源的详细描述,可以在网站中找到。
2.4
回调机制
回调机制是设计来克服低
ID
客户端不能接收输入的连接的,这样客户端之间就能共享它们的文件
。机制
很简单:假如客户端
A
和
B
都连接到同一个
eMule
服务器,
A
需要的文件在
B<
/p>
上,但
B
是低
I
D
的,
A
可以向服务器发送一个回调请
求(见
6.2.13
节)
,请求服务器
叫
B
呼叫回它。服务器,已经有一个与
B
的打开的
TCP
连接,发送一个回调
请求消息(见
6.2.14
节)到
B<
/p>
,为它提供
A
的
IP
和端口。
B
就能连
接到
A
并发送文件,没有给服务器增加负担。很明显,
只有高
ID
客户端可以要求低
ID
p>
客户端回调(低
ID
客户端是没有接收输入
连接的能力的)
。图
2.6
图解了回调
消息交换。
也有允许两个低
ID
客户端交换文件的能力,通过它们的服务器连接,用服务器接力。
大部分服务器不再
提供这个选项,因为它招致服务器的负担。
3
客户端服务器的
UDP
交流
eMu
le
客户端和服务器用不可靠的
UDP
服务来保持连接和增强搜索。
eMule
客户端产生
UDP
包的总量可
以达到它发送包的总数目的
p>
5% -
这些根据客户端服务器列表中服务器的数目,客户端下载
列表中每个文
件的源数目和用户执行的搜索数目而定。
UDP<
/p>
包通过计时器触发,计时器每
100ms
过期,有一个单独的
线程负责发送
UDP
输送结果,以每秒
10
个
UDP
p>
的最大速率。
3.1
服务器保持连接和状态信息
客户端周期性验证它服务器列表中的服务器状态。验证是通
过发送
UDP
服务器状态请求(见
6.
3.3
节)
和
UDP
< br>服务器描述请求(见
6.3.7
节)消息完成的。这里描
述的简单保持连接计划每小时产生不超过几
打包。任何情况下,包的最大速率是每秒
p>
0.2
个包(或每
5
秒一个包)
。当检查服务器的状态时,客户端
会首先发送一个
服务器状态请求消息,接着,每两次试图(发送一个服务器状态请求)中就发送一次服务
器描述请求,见图
3.1
。
客户端发送的服务器状态请求中
包括一个随机数字,在服务器回应中返回。在服务器返回的数字与客户端
发送的要求中数
字不同的情况下,回应的信息就会被丢弃。每次发送到服务器的包是状态请求,客户端就
移动尝试计数器。任何来自服务器的消息(包括搜索结果)都重置尝试计数器。当尝试计数器达到一个可
配置的限制时,服务器就认为是死机,从客户端的服务器列表中删除。服务器回应包括几个数据项
:服务
器状态回应
(见
6.3.4
p>
)
包括服务器中当前用户数目和文件数目,
也包括服务器的软件和硬件限制
(见
1.7
节)
。服务器描述回应(见
6.3.8
节)包括服务器名称和一个短的描述字符串。图
3.2
演示
了客户端和活
动服务器中满连接序列的消息流。