必知的技术知识:eDonkey协议

简介: 必知的技术知识:eDonkey协议

-->


1.简介


ED2K 协议 用于对等的客户端之间的通讯,众多对等的客户端形成了基于服务器的P2P文件共享网络。


下面几个词语用于包格式字符串:


u8 unsigned 8-bit integer


u16 unsigned 16-bit integer


u32 unsigned 32-bit integer


hash 16-bytes md4 checksum


string 16-bit integer (specifying string length) followed by the string


Taglist 32-bit integer (specifying number of tags) followed by the tags


一些定义:


part:


最大9500kb的文件片断,每个片断都有对应的MD4 PartHash.


chunk:


最大180kb的文件片断,每个片断都可以被远程的客户端请求


block:


chunk片断,每个片断被封装成单独的数据包在客户端之间传输。


2.Header 规格


+--------+--------+--------+--------+--------+--------+--------+--------+----


|protocol| packet length | packet data (length bytes)


+--------+--------+--------+--------+--------+--------+--------+--------+----


每个ED2K包协议以协议代码开始,后面跟着的是包的长度(32-bit unsigned的整数)。


现在的协议代码有下面三个:


PR_ED2K = 0xe3, //!< Standard, historical eDonkey2000 protocol


PR_EMULE = 0xc5, //!< eMule extended protocol


PR_ZLIB = 0xd4 //!< Packet payload is compressed with gzip


包数据通常以8-bit的代码开始,用于指示包的内容,如果以PR_ZLIB协议发送包,


包的数据经过压缩的。


3.客户端-服务端通讯


3.1 登陆服务器


客户端如果要连接到eDonkey2000服务器,发送OP_LOGINREQUEST给服务器.


OP_LOGINREQUEST = 0x01, //!< hashipporttags


这个包可能包括下面的标签(tags):


CT_NICK = 0x01, //!< nick


CT_VERSION = 0x11, //!< 0x3c


CT_PORT = 0x0f, //!< port


CT_MULEVERSION = 0xfb, //!< ver


CT_FLAGS = 0x20, //!< flags


flags可能包含下面信息:


FL_ZLIB = 0x01, //!< zlib compression support


FL_IPINLOGIN = 0x02, //!< Client sends its own ip during login


FL_AUXPORT = 0x04, //!< ?


FL_NEWTAGS = 0x08, //!< support for new-styled eMule tags


FL_UNICODE = 0x10 //!< support for unicode


对一个良好格式的OP_LOGINREQUEST包,服务器先以这个包报告的监听端口尝试连接到发送这个数据包的客户端,


之后如果服务器收到一个OP_HELLOANSWER包,说明连接成功,那么服务为该客户端分配一个高ID,否则可能是因为某些原因连接失败,那么//代码效果参考:http://www.lyjsj.net.cn/wx/art_24177.html

为该客户端分配一个低ID。

服务器发送下面的数据包通知客户端连接已经建立,同时也提供了和服务器有关的更新信息。


OP_SERVERMESSAGE = 0x38, //!< lenmessage


OP_SERVERSTATUS = 0x34, //!< usersfiles


OP_IDCHANGE = 0x40 //!< newid


注意:Lugdunum 16.44+服务器(什么来的?)发送一个附加的u32的ID_CHANGE数据包,包含了一些支持特性,包括:


FL_ZLIB = 0x01, //!< zlib compression support


FL_NEWTAGS = 0x08, //!< support for new-styled eMule tags


FL_UNICODE = 0x10 //!< support for unicode


3.2 更新服务器列表和信息


和服务器建立连接之后,客户端可以象服务器请求其他信息,象服务器列表:


OP_GETSERVERLIST = 0x14, //!< (no payload)


服务器用下面的包回应:


OP_SERVERLIST = 0x32, //!< count【{ipport}count】


OP_SERVERIDENT = 0x41, //!< hashipporttags


后面包含着下面的tags:


CT_SERVERNAME = 0x01, //!< name


CT_SERVERDESC = 0x0b //!< desc


3.2 发布共享文件


和服务器建立连接之后,客户端必须用OP_OFFERFILES包发布共享文件,如果服务器支持的话这些包必须被压缩以节省带宽。


//! count【{filehashipporttags}】


OP_OFFERFILES = 0x15,


这个包可能包含下面的tags:


CT_FILENAME = 0x01, //!< name


CT_FILESIZE = 0x02, //!< size


CT_FILETYPE = 0x03, //!< type


注意:


文件类型用字符串发送,下面的字符串会被识别:


#define FT_ED2K_AUDIO "Audio" //!< mp3/ogg/wma etc


#define FT_ED2K_VIDEO "Video" //!< avi/mpg/mpeg/wmv etc


#define FT_ED2K_IMAGE "Image" //!< png/jpg/gif/tiff etc


#define FT_ED2K_DOCUMENT "Doc" //!< txt/doc/rtf etc


#define FT_ED2K_PROGRAM "Pro" //!< exe/bin/cue/iso etc


这个包在下面时机会被发送:


.拥有一个共享文件列表,并连接到服务器的时候。


.添加新的共享文件的时候。


.As empty packet, as server keep-alive packet at regular intervals Additionally,可以用两对特殊的IP/PORT 值来指示共享的文件是部分的还是完整的。


FL_COMPLETE_ID = 0xfcfcfcfc, //!< File is complete - send this as ID


FL_COMPLETE_PORT = 0xfcfc, //!< File is complete - send this as port


FL_PARTIAL_ID = 0xfbfbfbfb, //!< File is partial - send this as ID


FL_PARTIAL_PORT = 0xfbfb //!< File is partial - send this as port


3.3 搜索


搜索在eDonkey2000网络是基于服务器的。客户端发送SEARCHR包给服务器,接着服务器返回一个或多个SEARCHRESULT包。这些都只是和当前连接的服务器的TCP层进行。但是,客户端也可以用GLOBSEARCH代码,通过UDP发送相同的请求包给所有已经的服务器,之后服务器也会用 GLOBSEARCHRES包回应(也是UDP)。


OP_SEARCH = 0x16, //!<


//! count【{hashidporttags}】


OP_SEARCHRESULT = 0x33,


搜索结果可能包含下面的tags:


CT_FILENAME = 0x01, //!< name


CT_FILESIZE = 0x02, //!< size


CT_FILETYPE = 0x03, //!< type


CT_SOURCES = 0x15, //!< numsrc


CT_COMPLSRC = 0x30, //!< numcomplsrc


4.客户端 - 客户端通信


4.1 get-to-know-you chit-chat


为了初始化和远程客户端的连接,客户端先要发送 Hello 包,


OP_HELLO = 0x01, //!< hashipporttags


Hello 可以 包含下面的 tags:


CT_NICK = 0x01, //!< nick


CT_PORT = 0x0f, //!< port


CT_MULEVERSION = 0xfb, //!< ver


CT_MODSTR = 0x55, //!< modstring


CT_UDPPORTS = 0xf9, //!< kadudpported2kudpport


CT_MISCFEATURES = 0xfa, //!< features bitset


对OP_HELLO正确的回应是OP_HELLOANSWER。这个HelloAnswer包的格式和OP_HELLO是一样的,只是HelloAnswer还包括了8-bit的hash长度。这个域的值必须是0x0f。


CT_MULEVERSION是一个32-bit的值,下面是bits的意义:


1 2 3 4 5 【bytes】


11111111222222233333334445555555 【bits】


00000000000000001010101100000000 eMule 42g version info


| | | | +---- Build version (unused by eMule)


| | | +--------- Update version 6 (a = 0, g = 6)


| | +-------------- Minor version 42


| +--------------------- Major version (unused by eMule)


+---------------------------- Compatible Client ID (CS_EMULE = 0x00)


如果两个客户端是eMule-compatible兼容的,那么他们必须交换MuleInfo包:


OP_MULEINFO = 0x01, //!< clientverprotvertags


OP_MULEINFOANSWER = 0x02 //!< clientverprotvertags


注意:所有这两个包都是用PR_EMULE来发送的。


在MuleInfo包里面的tags有:


CT_COMPRESSION = 0x20, //!< u32 compression version


CT_UDPPORT = 0x21, //!< u32 udp port


CT_UDPVER = 0x22, //!< u32 udp protocol version


CT_SOURCEEXCH = 0x23, //!< u32 source exchange version


CT_COMMENTS = 0x24, //!< u32 comment version


CT_EXTREQ = 0x25, //!< u32 extended request version


CT_COMPATCLIENT = 0x26, //!< u32 compatible client ID


CT_FEATURES = 0x27, //!< u32 supported features bitset


CT_MODVERSION = 0x55, //!< modversion (may also be int)


CT_MODPLUS = 0x99, //!< mh? (Source: eMule+ Forums ... )


CT_L2HAC = 0x3e, //!< mh? (Source: eMule+ Forums ... )


Feature 集标志为 是32-bit 值,意义如下:


12345678123456781234567812345678


00000100000100110011001000011110 eMule 43b


00110100000100110011001000011110 eMule 44b


11123333444455556666777788889abc


| | | | | | | | |||+-- Preview


| | | | | | | | ||+--- Multipacket


| | | | | | | | |+---- No `view shared files' supported


| | | | | | | | +----- Peercache


| | | | | | | +-------- Comments


| | | | | | +----------- Extended requests


| | | | | +---------------- Source exchange


| | | | +-------------------- Secure ident


| | | +----------------------- Data compression version


| | +--------------------------- UDP version


| +------------------------------ Unicode


+-------------------------------- AICH version (0 - not supported)


4.2 请求一个文件


在完成入 4.1所描述的握手之后,客户端现在可以请求一个文件了。这个由ReqFile包来完成。


OP_REQFILE = 0x58, //!< hash


OP_FILENAME和 OP_FILEDESC回应ReqFile


OP_FILENAME = 0x59, //!< hashlenname


OP_FILEDESC = 0x61, //!< ratinglencomment


接收了上面的数据包之后,下载方客户端发送SETREQFILEID 把刚才请求的文件绑定到一个hash上,这意味着现在客户端被绑定到被请求的hash上,直到它接受到它所请求的东西。


FileDesc用 PR_EMULE发送,但并不包含描述所属的文件的hash,然而,由于它经常跟着OP_FILENAME发送,所以客户端可以假定FileDesc属于最近所请求的那个文件。


发送这个包之后客户端会期望得到回应是OP_FILESTATUS


OP_REQFILE_STATUS = 0x50, //!< hashcountpartmap


如果上传方客户端认识到它并没有共享被要求上传的文件,那么它会发送OP_REQFILE_NOFILE。File status包含了有效parts的partmap.这被定义为为一个bitfield,每个bit代表了一个ED2K part(由ED2K_PARTSIZE定义).多处理的bit被0填充。


先于bitset的count指示了总的parts的数量。注意sending partmap完全是可选,并且只有当然共享文件是部分的才可以发送,如果共享文件是完整的,那么partmap将被忽略.


OP_REQFILE_NOFILE = 0x48, //!< hash


如果下载方客户端需要一个文件的hashset,它可以通过发送OP_REQHASHSET向上传方请求。期望得到的回应是OP_HASHSET


OP_REQHASHSET = 0x51, //!< hash


OP_HASHSET = 0x52, //!< hashcnt【cntparthash】


在这之后,请求方发送OP_STARTUPLOADREQ。被请求方要么用OP_ACCEPTUPLOADREQ回应(如果我们能开始正确的上传),要么用OP_QUEUERANKING回应,说明请求方的请求已经被插入到上传队列里了。


OP_STARTUPLOADREQ = 0x54, //!< may contain hash (emule)


OP_ACCEPTUPLOADREQ = 0x55, //!< Empty


OP_QUEUERANKING = 0x5c, //!< queueranking


4.3 上传文件数据


接收到OP_ACCEPTUPLOADREQ之后,下载方客户端将会继续请求chunks。在 eDonkey2000 网络,一个chunck的大小是180k。用OP_REQCHUNKS包请求chunks。


OP_REQCHUNKS = 0x47, //!< hash【3begin】【3end】


这个包包含了被请求的chunks的3个开始偏移和3个结束偏移。ED2K 数据 将结束偏移定义为是唯一的(exclusive),因此象(0, 0)这样的范围被认为是无效的范围。如果下载方客户断请求少于3个chunks,那么这个包可以包含象(0,0)的保留范围来指示。


接收到OP_REQCHUNKS后,上传方客户断开始发送数据。被请求的chunks 被分成最大10kb的blocks,每个blocks用OP_SENDINGCHUNK作为单独的数据包传送,


OP_SENDINGCHUNK = 0x46, //!< hashbeginend


当下载方客户端决定不再接收任何数据的时候,它可以发送OP_CANCELTRANSFER包给上传方客户端。


OP_CANCELTRANSFER = 0x56 //!< empty


5 低ID客户端


低ID客户端在ed2k网络被定义这样的客户端:


无法接收外部连接的客户断。这样的客户端只能自己主动创建外部连接。连接低ID客户端唯一的方法就是通过服务器的回调,只要这个客户端已经连接到服务器。只有连接到同样的服务器的客户端才能连接到低ID客户端。低ID客户端在网络中被分配小于0x00ffffff的ID。这也是很多地方我们把IP称为ID的原因,因为如果客户端的ID大于0x00ffffff,那么ID就是该客户端的IP,否则就是该客户端的回调ID,由服务器分配。


5.1 连接到低ID客户端


要想连接到低ID客户端,必须发送OP_REQCALLBACK包给当前连接的服务器,这个包含了我们要连接的客户端的ID。


OP_REQCALLBACK = 0x1c, //!< id


如果被要求连接的低ID客户端已经连接到服务器,那么服务器发送OP_CBREQUESTED包给它。


OP_CBREQUESTED = 0x35, //!< iptcpport


如果被要求连接的低ID客户端由于某些原因没有连接到这个服务器,那么服务器将会回应OP_CALLBACKFAIL.


OP_CALLBACKFAIL = 0x36 //!< empty

相关文章
|
Web App开发 网络协议 关系型数据库
深度解析TCP协议:特点、应用场景及市面上常见软件案例
深度解析TCP协议:特点、应用场景及市面上常见软件案例
2208 1
深度解析TCP协议:特点、应用场景及市面上常见软件案例
|
SQL IDE Java
IDEA控制台如何查看格式化的SQL(MyBatis Log插件)
IDEA控制台如何查看格式化的SQL(MyBatis Log插件)
3512 0
|
SQL 网络协议 关系型数据库
|
JavaScript 前端开发 HTML5
PDF转图片,PDF转JPG/PNG,完全由JS实现
原理 使用pdf.js预览图片,pdf.js将pdf通过canvas将每一页渲染出来,然后我们通过canvas的toDataURL方法保存为jpg或png格式。pdf.js是Mozilla开源的一个js库,无需任何本地支持就可以在浏览器上显示pdf文档。
16718 1
|
9月前
|
关系型数据库 MySQL 分布式数据库
航天壹进制 PolarDB-X 1.0(DRDS) 数据备份容灾解决方案
本方案基于航天壹进制黑方系统,结合MySQL逻辑备份技术,为阿里云PolarDB-X 1.0(DRDS)构建非侵入式、高可靠的数据备份与恢复体系,支持全量备份、AES-256加密、压缩重删及灵活策略管理,兼容RDS MySQL操作习惯,保障数据安全与业务连续性。
|
缓存 JSON API
淘宝关键词搜索 API 接口详解与示例
淘宝关键词搜索API(taobao.items.search)助力开发者高效获取商品数据,支持分页、筛选与排序。本文详解接口调用流程、签名机制及Python实现,涵盖权限申请、代码示例与常见问题解决方案,助你快速构建电商应用。
|
机器学习/深度学习 数据采集 算法
深度学习之路径优化与车辆调度
基于深度学习的路径优化与车辆调度技术在交通管理、物流配送、公共交通、共享出行等领域具有重要应用价值。这些技术利用深度学习模型处理复杂的交通数据、实时信息以及用户需求,旨在提高运输效率、降低成本、减少拥堵并提升服务质量。
912 0
|
弹性计算 智能网卡 网络安全
一文带你了解阿里云云网络的十年演进之路
伴随着大型和超大型企业陆续上云,更丰富行业场景和更多样的服务运行在阿里云上,对云网络的规模、性能、弹性提出了更极致的要求,驱使着云网络不断持续优化,从经典网络到专有网络,控制面从1.0到3.0,数据面从内部服务去网关,边界网关硬件化,全面拥抱智能网卡,再到业务网元虚拟化,走上一条“螺旋”上升的路线。
|
JSON 人工智能 数据可视化
实用工具推荐第二期结合deepseek的思维导图开源免费工具 JSON 可视化工具
JSON 数据可视化为交互式的树形图或图形,帮助直观理解文件结构和模块之间的联系。
1563 19
|
传感器 算法 机器人
《深度解析基于 C++的机器人操作系统(ROS)底层原理与开发之道》
在科技飞速发展的今天,机器人技术正在各个领域掀起革命。机器人操作系统(ROS)作为开源的机器人软件框架,占据着重要地位。C++作为ROS中常用的编程语言,其在ROS中的底层原理和开发方法对于机器人开发者至关重要。本文介绍了ROS的架构基础、C++在ROS中的节点和服务开发原理、参数管理以及开发方法与实践要点,帮助开发者深入了解和掌握ROS的开发技术。
1241 41