Libtorrent源代码阅读小札

来源:互联网 发布:紫光手电筒下载软件 编辑:程序博客网 时间:2024/04/29 12:25

 

ses.start_dht()->ses_imp.start_dht()session_implsession的实现。跟踪进去,m_dht = new dht::dht_tracker(m_io_service, m_dht_settings, m_listen_interface.address(), startup_state)session_impl会在start_dht里面创建一个dht_tracker对象,这里的参数需要好好看一下,首先是m_io_service,这是boost::asio库中的一个对象,简单来说就是提供io服务,每一个利用boost::asio库的程序都需要拥有这样一个对象,它负责与操作系统内核的通信互动,有点类似于手机中的手机卡一样,虽然手机已经实现了无线通信的功能,但是,需要手机卡才能加入到虚线网络,才能获取我们所需的服务。可以看到,这个io_service对象放在session_impl中,意味着一个session只会拥有一个io_service对象。第二个参数相当于dht网络的配置文件。第三个参数为IP地址。第四个参数为携带启动节点信息的对象。继续跟踪,看看dht_tracker在构造函数中会做些什么事。跟踪进去后发现,dht_tracker在构造函数中会进行一系列的初始化,那么我们挑选几个比较重要的初始化动作,看看这些传进去的参数最终都作为何用。第一个:m_strand(ios),原来dht_tracker会维护一个boost::asio::strand对象,此对象有何用处?它是用来保证,通过strand对象包装的threads,对线性有序的执行,主要是用来实现线程同步的,这个先分析到这里,有时间再去深究一下。第二个: m_socket(ios, udp::endpoint(listen_interface, settings.service_port)),我们看到了传进来的IP地址,以及dht_setting原来可以初始化一个udp套接字。第三个:m_dht(bind(&dht_tracker::send_packet, this, _1), settings, read_id(bootstrap))m_dht何许物也?原来它是一个node_impl对象,这名字取得还真是让人难以望文生义啊!dht_tracker又要去初始化node_impl对象,我们现在来稍微理一理dht_trackernode_impl之间的关系,查看一下接口,我们可以直观的认为dht_tracker是用来管理dht网络和racker通信的,从实现看来,dht网络的实现需要借助于node_impl,至于更深层的关系有待接下来的深入跟踪。来看参数,第一个参数为一个函数对象,我们有必要了解一下此函数对象的signature,我借用boost来表达一下:boost::function<void(msg const&)>。直观来看,此函数对象的作用应该是发送一个msg,啊呀,好像找到了libtorrent数据通信的一点端倪了,如果没有猜错,那么send_packet里面应该能找到我们熟悉的socket通信了,真是不容易啊。带着激动的心情,我们进去看看。哇哇哇,果然不失所望啊,这里面别有洞天啊,看到了这么多熟悉的字眼“token”,“query,info_hash,ping,find_node”,“get_peer”……哈哈,熟悉dht的朋友应该会很兴奋,其余的就不用我说了吧。接下来就有一个问题了,这个函数究竟会被谁调用呢?我们来看看,它把send_packet包装成一个函数对象,作为node_impl对象的初始化参数传递出去,难道此函数会由node_impl来调用?继续前进。Node_impl对象的构造函数看起来稍微清爽一些,我们一个一个来看,m_settings(settings):这个setting就是dht_setting,传的够远啊,从session一路走来,经过session_impldht_tracker,这会又到了这里,真想它的终点在那里,此为后话,留为存照。m_id(node_id ? *node_id : generate_id()):这个不用多说,node_id是也。m_table(m_id, 8, settings):哈哈,dht路由表,终于看到你啦。m_rpc(bind(&node_impl::incoming_request, this, _1), m_id, m_table, f):原来node_impl还会去初始化一个rpc_manager对象,哇,又看到了久违的boost::bind了,不用说又有函数对象产生了,看看这次又会有什么发现。还是用boost::function来表述吧,查证以后原来还是boost::function<void(msg const&)>,我们可以看到这次包装的是node_impl::incoming_request,那么里面又会发生什么事情呢?会不会又有惊喜啊?来看看吧。哇哇,熟悉的switch..case语句,还用说什么,无以言表啊……到这里我们找到了dht网络最核心的sendreceive。下面只需要知道究竟是谁调用的,就彻底明晰了。好,这样来看,这两个函数对象都会传送给rpc_manager,这个rcp_manager到底是怎样一个神秘角色,dht_trackernode_impl里面的函数都归它调用,让我们来揭开它的神秘面纱吧。跟踪到rpc_manager的构造函数,发现也只是些初始化动作,其中我们最关心的两个函数对象分别被赋值给m_sendm_incoming。得,追踪到这里,已经到了绝路了。那么,这两个对象又是什么时候调用的呢?虽然已经没有明显的线索,但是我们可以大致确定这两个函数对象只能是rpc_manager来调用了,那就ctrl+f吧,来看看他们都会出现在哪些地方。

Rpc_manager::invoke(int message_id, udp::endpoint target_addr, shared_ptr<observer> o)

{

……

o->send(m);

……

m_send(m);

……

}

 

Rpc_manager::reply(msg& m, msg const& reply_to)

{

……

m_send(m);

……

}

 

void rpc_manager::reply_with_ping(msg& m, msg const& reply_to)

{

……

m_send(m);

……

}

哇,这么多地方调用,看来不能以这种方式跟踪了,我们得回退到client_test,接着往下读了。

 

///////////////////////////////////////////////////////

首先是Rpc_manager::Invoke(),调用者如下:

get_peers_observer::reply()

find_data_observer::invoke()

 

announce_fun

 

refresh::invoke_pings_or_finish()

refresh::invoke()

find_data::invoke()

closest_nodes::invoke()