首页 | 乐园 | 淘宝店 | 社区 | 电驴 | 网页游戏 | 网址大全

VeryCD / 社区 / 电驴软件开发 / 精华

资源管理小组

相关主题

主题: emule 中的CallBack机制

相关分类: codeanalyze emule
« 上一页 1 2

godLaugh (组长) 2007/11/16 14:45:25 顶楼 举报

一、基础知识

大家都知道,emule运行后客户端需要立刻连接ed服务器,以确定该emule client 端是HighID还是LowID(如果是LowID,下载速度会受到一定的影响)。

大部分情况来说,外网用户的emule都是HighID,而内网用户是LowID,但也有以下例外:外网用户的机器如果有防火墙把自己的emule tcp listen服务端口禁掉了的话,那么就只能拿到LowID;内网用户如果靠静态映射或UPNP动态映射成功的话,也可以拿到HighID(大部分有经验的驴友都会很注意观察自己的emule主窗口右下角的emule连接图标,验证自己是否拿到HighID)。

  既然每个emule客户端有HighID/LowID两种情况,那么对于整个P2P网络应用来说,按照连接的发起方和接收方组合,就会有以下四种情况连接:

1) HighID --> HighID
2) HighID --> LowID
3) LowID --> LowID
4) LowID --> HighID

其中第 1,4 种情况最简单,往接收方HighID的TCP Listen端口直接发连接,连接成功后,双方就开始通信;但是对于第 2,3 种情况来说,可就不是那么简单了。其中第3中情况就是大家都都知道的Low2Low内网穿透的实现(可以通过TCP穿透实现,也可以实现UDP穿透后模拟TCP,VeryCD emule的Low2Low传输中实现的就是后一种方案,具体可参考VeryCD emule Low2Low实现原理和方法介绍)。

二、emule 的 HighID->LowID
今天我主要和大家介绍一下emule中是如何实现(HighID-->LowID)的,其实也很简单,就是emule callback机制,简单的来说就是:由于HighID无法直接主动发起连接到LowID,因此也要靠一个第三方的搭桥,由这个第三方去通知该LowID主动发连接到这个HighID,连接成功后即可通信。
emule中的HighID-->LowID的通信既有TCP,也有UDP; 既有靠ed服务器完成HighID-->LowID,也有靠LowID的buddy来完成HighID-->LowID。下面我将分别以代码来仔细介绍:

2.1 Tcp callback over Emule.Server

这种情况的Callback是High.A 和 Low.B 必须在同一emule Server上, 我们先假定有HighID.A要连接LowID.B,通信连接过程图如下:
IPB Image

协议参数List:
①<Low.B 的 32bit Id>
②<High.A IP><High.A Tcp Port>
③直接发送连接,进行握手协议

具体框架代码List:
①High.A 通过tcp向Server 发 OP_CALLBACKREQUEST,
参数:<Low.B 的 32bit Id>

CUpDownClient::TryToConnect( ... ) //High.A TryToConnect Low.B
{
  if (theApp.serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort))
  {
    Packet* packet = new Packet(OP_CALLBACKREQUEST,4);
  }
  ...
  SetDownloadState( DS_WAITCALLBACK );
}

② Low.B 收到 Server 发送的OP_CALLBACKREQUESTED 后, 然后向 High.A 发送 TryToConnect ,完成反向连接
CServerSocket::ProcessPacket( ... )
{
  ...
  case OP_CALLBACKREQUESTED
  {
    ...
    client->TryToConnect();
  }
}

③ 如果 Server 无法通知 Low.B ,则向 High.A 发送 OP_CALLBACK_FAIL

2.2 基于Buddy的[TCP]CallBack
基于Buddy的CallBack 可能是emule中独有的,emule中的 Buddy 机制是一个很有意思的机制,这个Buddy机制其实就是为了协助LowID能更好的与HighId通信而实现的。具体怎么找Buddy的过程我下次另外分析。这里大家只要把LowID的Buddy看成是一个HighID的emule客户端即可,他和一个LowID的Buddy互为Buddy,形成“兄弟结盟”一样。

通信顺序过程图如下:
IPB Image

图中我们可以看到,基于Buddy完成Tcp CallBack的前提条件是:
1) LowID.B 必须找到一个稳定的Buddy HighID.D
2) HighID.A 必须已知 LowID.B 的Buddy High.D 的对外IP.Port信息

协议参数List:
① <Low.B ~KadId><File Id><High.A Port>
② <Low.B ~KadId><File Id><High.A ip> <HighA.port>
③ 直接发Connect,进行握手

具体框架代码List:
①/ High.A 向 Low.B 的 Buddy High.D 发送[UDP] KADEMLIA_CALLBACK_REQ
协议参数: <Low.B ~KadId><File Id><High.A Port>
CUpDownClient::TryToConnect( ... ) //High.A TryToConnect Low.B
{
  ...
  if [ A 已知 B的Buddy D的IP/Port]
    Packet* packet = new Packet(&bio, OP_KADEMLIAHEADER);
    packet->opcode = KADEMLIA_CALLBACK_REQ;
    theApp.clientudp->SendPacket(packet, GetBuddyIP(), GetBuddyPort(), false, NULL); // kad doesnt supports obfuscation yet
  else[基于Kad 网络Search B的Buddy High.D 的IP/Port]
    //Create search to find buddy.
    Kademlia::CSearch *findSource = new Kademlia::CSearch;
    findSource->SetSearchTypes(Kademlia::CSearch::FINDSOURCE);
    findSource->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
    findSource->AddFileID(Kademlia::CUInt128(reqfile->GetFileHash()));
    if(Kademlia::CSearchManager::StartSearch(findSource))
    //Peer.B DownState 从 DS_WAITCALLBACK -> DS_WAITCALLBACKKAD
}
②/ High.D 处理 KADEMLIA_CALLBACK_REQ ,通过[tcp] 向其Buddy Low.B 发 OP_CALLBACK

CKademliaUDPListener::Process_KADEMLIA_CALLBACK_REQ
{
  ...
  Packet* pPacket = new Packet(&fileIO2, OP_EMULEPROT, OP_CALLBACK);//OP_CALLBACK
}

OP_CALLBACK 协议参数:
<HASH 16> <HASH 16><uint 32> <uint 16>
<Low.B ~KadId> <File Id> <High.A ip> <HighA.port>

③ Low.B 处理收到的 OP_CALLBACK , 向 High.A 发送Tcp 连接 [反向连接到此结束]
CClientReqSocket::ProcessExtPacket( )
{
  data.ReadUInt128(&check);
  check.Xor(Kademlia::CUInt128(true)); // 这里的Id会再反向一次
  ...
  callback = theApp.clientlist->FindClientByIP(ntohl(ip), tcp);
  if( callback == NULL )
  {
    callback = new CUpDownClient(NULL,tcp,ip,0,0);
    theApp.clientlist->AddClient(callback);
  }
  callback->TryToConnect(true);
}

未完,待续...

转载请注明出处: VeryCD emule 软件开发组 emuledev@VeryCD.com

分享到开心网  分享到校内  收藏到QQ书签    订阅本主題RSS更新  美味书签

2008/05/22 16:45:31godLaugh 最后编辑 | 查看全部

xLinker 2007/11/16 15:32:00 2楼 举报

沙发,顶!!


[0] [0] [回复]

尖叫狂 2007/12/21 01:17:02 3楼 举报

看不懂说~~~


[+1] [0] [回复]

xfdavid 2008/03/19 16:51:02 4楼 举报

L2L才是精华。。。精华的东西呢???


[+1] [0] [回复]

tomosak 2008/04/03 10:07:07 5楼 举报

其中第1,4种情况最简单,往接收方HighID的TCP Listen端口直接发连接,连接成功后,双方就开始通信;但是对于第3,4种情况来说,可就不是那么简单了

这里是不是有错啊?


[0] [0] [回复]

ewolfok 2008/05/15 13:30:59 6楼 举报

有了这篇文章,理解TryToConnect()这个函数就容易多了!

多谢组长的精品文章。


[0] [0] [回复]

godLaugh (组长) 2008/05/22 16:46:54 7楼 举报

to tomosak: 之前确实写错了,现在已经更正


[0] [0] [回复]

solidyjd 2008/08/05 22:53:04 8楼 举报

强帖,留名做个记号


[0] [0] [回复]

zerofire 2008/10/22 14:40:37 9楼 举报

回头研究~~


[0] [0] [回复]

azuregos 2008/12/27 18:19:02 10楼 举报

没看懂啊~~~太专业了


[0] [0] [回复]

mybdxz800 2009/01/19 14:06:58 11楼 举报

好复杂的技术贴啊
是不是教育网用户都是LOW ID啊


[0] [0] [回复]

第四阶级 2009/01/19 14:19:25 12楼 举报

太专业了


[0] [0] [回复]

13楼已被删除

liqilin2009 2009/01/29 08:35:51 14楼 举报

对emule架构进行介绍吧,自上而下的描述会让人更有收获。凝聚众人力量emule会更强


[0] [0] [回复]

yiqucanyang 2009/01/29 08:38:12 15楼 举报

~~~太专业了


[0] [0] [回复]

bfelite 2009/02/03 20:32:56 16楼 举报

我们学校都是独立的公网IP,以前刚开网的时候是HighID,现在不知为什么就变成LowID了。


[0] [0] [回复]

zyhmichael 2009/02/03 20:54:44 17楼 举报

为什么到了铜光盘就不动了呢!?


[0] [0] [回复]

librav 2009/02/03 20:55:24 18楼 举报

看的眼花了!~~~~~


[0] [0] [回复]

loumanak47 2009/02/04 09:20:58 19楼 举报

绝对专业,看花眼了


[0] [0] [回复]

20-26楼已被删除

sghcpt 2009/05/04 18:10:54 27楼 举报

什么時候出來呀。和期待呀。希望快點快點。。。。。。。


[0] [0] [回复]

28楼已被删除

chenwupiaoxue 2009/07/27 10:21:13 29楼 举报

请问怎么通过emule主窗口右下角的emule连接图标识别确定该emule client 端是HighID还是LowID(如果是LowID,下载速度会受到一定的影响)。


[0] [0] [回复]

2009/07/28 11:29:42chenwupiaoxue 最后编辑 | 查看全部

godLaugh (组长) 2009/07/28 14:39:18 30楼 举报

@chenwupiaoxue
这里有详细介绍
http://www.emule.org.cn/faq/doc/icons.htm

简单理解就是绿色是HighID,黄色是Lowid,红色就是没连上


[0] [0] [回复]

« 上一页 1 2


返回组首页

快速回复

(?) 附件上传

关于我们 | 诚聘英才 | 著作权声明 | 合作信息 | 广告事务
沪ICP备05001009号
©2003 - 2009 VeryCD.com Some Rights Reserved.