这部分重点介绍EOS中的服务器端部分nodeos启动之后开启的另外一个重要的插件——net_plugin,这个插件主要负责服务器在网络中的接入、同步区块信息、断开等功能。对于这个插件,首先从其类的定义开始了解。
1 | class net_plugin : public appbase::plugin<net_plugin> |
net_plugin插件的代码还是比较容易理解的,net_plugin的初始化函数非常简单,代码如下:
1 | net_plugin::net_plugin() |
初始化函数中生成了一阁net_plugin_impl的实例,随后将my的指针赋值给了net_plugin_impl类中的定义的静态指针,这个静态指针的定义如下:
1 | static net_plugin_impl *my_impl; |
再nodeos的main函数中,net_plugin首先会初始化,随后调用其plugin_initialize函数和EOS中lugin之producer_plugin的介绍的procuder_plugin类初始化方式时一样的,先寻找这个插件依赖的插件,然后初始化依赖的插件、一些启动参数,设置心跳计时器等。
nodeos中初始化完毕,随后调用net_plugin的plugin_startup函数,该函数代码如下:
1 | void net_plugin::plugin_startup() { |
首先打开监听的端口号,设置相关协议,随后绑定端口号,然后开始监听网络中的信息,同时让本端点连接到网络中的种子节点,以此连接EOS中的p2p网络。这里面最重要的2个函数是 my->start_listen_loop()以及my->start_monitors()函数,my->start_listen_loop,通过函数名称可以断定主要用来不断地从网络中监听网络中发送的信息,my->start_monitors()应该是进行监听,但是到底监听什么,我们还不得而知。
这里暂时先不对net_plugin_impl进行具体解析,因为这并不影响我们对这两个函数的分析,另外一方面,net_plugin_impl的介绍对于这两个函数的分析,帮助不大。
因此,我们直接进入start_listen_loop函数一探究竟。
1 | /// 该函数循环监听信息 |
start_listen_loop()函数中最重要的一个函数是,监听到消息之后的start_session()函数,表示监听到了新的链接,于是开始会话。start_session()函数内容如下所示。
1 | bool net_plugin_impl::start_session(const connection_ptr& con) { |
其中重要的是start_read_message,即回话过程中读取数据,即start_read_message()函数,其具体内容如下所示。
1 | void net_plugin_impl::start_read_message(const connection_ptr& conn) { |
抛去其中try catch语句,我们重点看到conn->process_next_message函数,这个函数正如注释所说,从接受到的pending_message_buffer中处理数据,我们继续追踪这个处理函数,如下所示。
1 | // 该函数用于数据同步,使用中心消息处理系统处理数据 |
其中重要的是msg_handler类型,这里面分别针对消息不同的类型做不同的处理,首先查看针对如果msg中包含了signed_block,则进入处理block函数;如果msg中包含packed_transaction,则进入处理trx的函数。首先查看msg_handler是如何处理signed_block的,处理区块的函数如下。收到区块之后验证区块,验证通过则接受区块,验证失败则拒绝区块。
1 | // 如果从网络中收到一个区块,执行相应的处理 |
对交易的验证与对区块的处理方式相同,验证交易,如果本地存在此交易,则丢弃,否则开始验证交易,若验证通过则接受交易并广播交易,否则拒绝交易。
1 | void net_plugin_impl::handle_message(const connection_ptr& c, const packed_transaction_ptr& trx) { |
至此,net_plugin以及net_plugin_impl插件中的比较重要的函数已经分析完毕,由于其中细节错综复杂,因此在分析过程中抓住主要脉络进行分析,对于其他细节内容并没有深究。