eMule电驴eDonkey源代码精辟分析

最近给一家公司写一个类似电驴的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行为都在这里了.当然这只是

通信的开始,后续代码分析我会在今后的博客中为大家见讲解

你可能感兴趣的:(socket,server,null,query,deprecated,代码分析)