最近给一家公司写一个类似电驴的P2P客户端.写的相当的累,但是收获也很大,对电驴的代码进行
了深入的分析,现在把所得贡献给大家,网上有很多对电驴协议的分析,其实有些地方是误导大家了,
中国的程序员还是很小家子气,就是怕别人超过自己.
进入正题,电驴的协议和各种常量参数定义在opcodes.h中,
#define OP_EDONKEYHEADER 0xE3
#define OP_KADEMLIAHEADER 0xE4
这是他的协议码,他大部分的通信包第一个字节都是OP_EDONKEYHEADER 0xE3,
这是他的客户端之间的协议
#define OP_HELLO 0x01 // 0x10<HASH 16><ID 4><PORT 2><1 Tag_set>
#define OP_SENDINGPART 0x46 // <HASH 16><von 4><bis 4><Daten len:(von-bis)>
#define OP_REQUESTPARTS 0x47 // <HASH 16><von[3] 4*3><bis[3] 4*3>
#define OP_FILEREQANSNOFIL 0x48 // <HASH 16>
#define OP_END_OF_DOWNLOAD 0x49 // <HASH 16>
#define OP_ASKSHAREDFILES 0x4A // (null)
#define OP_ASKSHAREDFILESANSWER 0x4B // <count 4>(<HASH 16><ID 4><PORT 2><1 Tag_set>)[count]
#define OP_HELLOANSWER 0x4C // <HASH 16><ID 4><PORT 2><1 Tag_set><SERVER_IP 4><SERVER_PORT 2>
#define OP_CHANGE_CLIENT_ID 0x4D // <ID_old 4><ID_new 4>
#define OP_MESSAGE 0x4E // <len 2><Message len>
#define OP_SETREQFILEID 0x4F // <HASH 16>
#define OP_FILESTATUS 0x50 // <HASH 16><count 2><status(bit array) len:((count+7)/8)>
#define OP_HASHSETREQUEST 0x51 // <HASH 16>
#define OP_HASHSETANSWER 0x52 // <count 2><HASH[count] 16*count>
#define OP_STARTUPLOADREQ 0x54 // <HASH 16>
#define OP_ACCEPTUPLOADREQ 0x55 // (null)
#define OP_CANCELTRANSFER 0x56 // (null)
#define OP_OUTOFPARTREQS 0x57 // (null)
#define OP_REQUESTFILENAME 0x58 // <HASH 16> (more correctly file_name_request)
#define OP_REQFILENAMEANSWER 0x59 // <HASH 16><len 4><NAME len>
#define OP_CHANGE_SLOT 0x5B // <HASH 16>
#define OP_QUEUERANK 0x5C // <wert 4> (slot index of the request)
#define OP_ASKSHAREDDIRS 0x5D // (null)
#define OP_ASKSHAREDFILESDIR 0x5E // <len 2><Directory len>
#define OP_ASKSHAREDDIRSANS 0x5F // <count 4>(<len 2><Directory len>)[count]
#define OP_ASKSHAREDFILESDIRANS 0x60 // <len 2><Directory len><count 4>(<HASH 16><ID 4><PORT 2><1 Tag_set>)[count]
#define OP_ASKSHAREDDENIEDANS 0x61 // (null)
这是他的客户端到服务器的通信协议
// client <-> server
#define OP_LOGINREQUEST 0x01 //<HASH 16><ID 4><PORT 2><1 Tag_set>
#define OP_REJECT 0x05 //(null)
#define OP_GETSERVERLIST 0x14 //(null)client->server
#define OP_OFFERFILES 0x15 // <count 4>(<HASH 16><ID 4><PORT 2><1 Tag_set>)[count]
#define OP_SEARCHREQUEST 0x16 // <Query_Tree>
#define OP_DISCONNECT 0x18 // (not verified)
#define OP_GETSOURCES 0x19 // <HASH 16>
#define OP_SEARCH_USER 0x1A // <Query_Tree>
#define OP_CALLBACKREQUEST 0x1C // <ID 4>
#define OP_QUERY_CHATS 0x1D // (deprecated not supported by server any longer)
#define OP_CHAT_MESSAGE 0x1E // (deprecated not supported by server any longer)
#define OP_JOIN_ROOM 0x1F // (deprecated not supported by server any longer)
#define OP_QUERY_MORE_RESULT 0x21 // (null)
#define OP_SERVERLIST 0x32 // <count 1>(<IP 4><PORT 2>)[count] server->client
#define OP_SEARCHRESULT 0x33 // <count 4>(<HASH 16><ID 4><PORT 2><1 Tag_set>)[count]
#define OP_SERVERSTATUS 0x34 // <USER 4><FILES 4>
#define OP_CALLBACKREQUESTED 0x35 // <IP 4><PORT 2>
#define OP_CALLBACK_FAIL 0x36 // (null notverified)
#define OP_SERVERMESSAGE 0x38 // <len 2><Message len>
#define OP_CHAT_ROOM_REQUEST 0x39 // (deprecated not supported by server any longer)
#define OP_CHAT_BROADCAST 0x3A // (deprecated not supported by server any longer)
#define OP_CHAT_USER_JOIN 0x3B // (deprecated not supported by server any longer)
#define OP_CHAT_USER_LEAVE 0x3C // (deprecated not supported by server any longer)
#define OP_CHAT_USER 0x3D // (deprecated not supported by server any longer)
#define OP_IDCHANGE 0x40 // <NEW_ID 4><server_flags 4><primary_tcp_port 4 (unused)><client_IP_address 4>
#define OP_SERVERIDENT 0x41 // <HASH 16><IP 4><PORT 2>{1 TAG_SET}
#define OP_FOUNDSOURCES 0x42 // <HASH 16><count 1>(<ID 4><PORT 2>)[count]
#define OP_USERS_LIST 0x43 // <count 4>(<HASH 16><ID 4><PORT 2><1 Tag_set>)[count]
#define OP_GETSOURCES_OBFU 0x23
#define OP_FOUNDSOURCES_OBFU 0x44
电驴的Socket网络通信部分写的超级搞笑,听我慢慢道来
首先EMSocket.h这个类是他的业务通信类
可以清楚的看到他的协议头部分是个#define PACKET_HEADER_SIZE 6字节
看他的接收是一个静态缓冲区static char GlobalReadBuffer[10*1024*1024];
10M大小
在接收时候大于8K的使用10M设置,小于8k的使用8K
uint32 recvbufferlimit = 2*ret;
if (recvbufferlimit > (10*1024*1024)) {
recvbufferlimit = (10*1024*1024);
} else if (recvbufferlimit < 8192) {
recvbufferlimit = 8192;
}
if (recvbufferlimit > m_uCurrentRecvBufferSize) {
SetSockOpt(SO_RCVBUF, &recvbufferlimit, sizeof(recvbufferlimit), SOL_SOCKET);
}
int ilen = sizeof(int);
GetSockOpt(SO_RCVBUF, &recvbufferlimit, &ilen, SOL_SOCKET);
发送的时候
Send(1300, 0, true);
以1300MTU发送.
然后在谈一下他的爷爷,他的爸爸CEncryptedStreamSocket先略去不讲
class CEncryptedStreamSocket : public CAsyncSocketEx
讲CAsyncSocketEx这个可是电驴最核心的通信类,他直接继承于MFC的祖宗CObject
大家注意我这里会讲到电驴SOCKET的命脉所在,这是在整个互联网上还没有人讲的,我最先发布
电驴的网络控制是在每一个CAsyncSocketEx中包含了一个窗口句柄,利用这个窗口来派发所有的
socket通信控制
这是他的SOCKET
struct t_AsyncSocketExData
{
SOCKET hSocket; //Socket handle
int nSocketIndex; //Index of socket, required by CAsyncSocketExHelperWindow
} m_SocketData;
这是他的那个消息窗口
struct t_AsyncSocketExThreadData
{
CAsyncSocketExHelperWindow *m_pHelperWindow;
int nInstanceCount;
DWORD nThreadId;
} *m_pLocalAsyncSocketExThreadData;
这是包含所有窗口句柄的链表
//List of the data structures for all threads
static struct t_AsyncSocketExThreadDataList
{
t_AsyncSocketExThreadDataList *pNext;
t_AsyncSocketExThreadData *pThreadData;
} *m_spAsyncSocketExThreadDataList;
然后大家去AsyncSocketEx.cpp中看
class CAsyncSocketExHelperWindow的类实现吧,他的所有的SOCKET行为都在这里了.当然这只是
通信的开始,后续代码分析我会在今后的博客中为大家见讲解