例子
这次的选择是以一个实际运营的项目做测试,其实我在以前的文章中也提到过这个应用,也许大家都并不陌生,它就是现在还比较火爆的剑侠3,一款多人在线的MMO游戏。网络上很久以前就流出了其部分的源代码,很久以前我也对它经过一定的分析,不过感觉到并没有修复和学习的必要,也就没有再看。现在想来最大的原因就是那份代码缺少的东西太多,就连一些基本的头文件都缺失,那么参考的意义就不大,除非有极深的兴趣和足够的精力。
这次选择的是几年前稍微完整的一份代码,当然也只是冲着研究和学习的目的,毕竟那么一个大型的项目还是有一定的研究价值,不过想要实际运行并没有那么容易,虽然一份可以32编译的版本,但我是索然无味的。其最大的原因,就是我想要将plain framework(PF)应用到这里面。其实从残缺的代码中可以看到其实确实比较重要的地方就是网络方面,而正好PF拥有这个能力,一切就自此开始了。
PF的网络
修复那流出并不太全的代码,最大的就是需要实现网络方面的接口,好在PF主要做这方面的,而在修改这部分代码之前,我还以为可能会费一番周折。可是经过一段时间的思考后,结果就如果下面的短短代码,一切都如同古语说的那样:大道至简!
// 这个线程池目前只用于重连 pf_sys::ThreadPool g_thread_pool(6); void reconnect( pf_net::connection::Basic *conn, const std::string &name, const std::string &ip, uint16_t port) { for (;;) { std::this_thread::sleep_for(std::chrono::milliseconds(5000)); KGLogPrintf(KGLOG_DEBUG, "reconnect: %s(%s:%d)", name.c_str(), ip.c_str(), port); auto r = conn->connect(ip.c_str(), port); if (r) { get_conn_mgr().add(conn); //线程不安全? get_conn_mgr().set_connection_name(conn->get_id(), name); conn->set_name(name); break; } } }; std::unique_ptr < pf_net::connection::manager::Connector > g_connector; // static bool g_connector_init{ false }; pf_net::connection::manager::Connector & get_conn_mgr() { if (is_null(g_connector)) { auto connector = new pf_net::connection::manager::Connector; unique_move(pf_net::connection::manager::Connector, connector, g_connector); g_connector->callback_disconnect([](pf_net::connection::Basic *conn){ auto flag = conn->get_param("no_reconnect"); // 如果设置了不自动重连... if (flag == true) return; std::string ip = conn->socket()->host(); if ('\0' == ip[0]) return; auto port = conn->socket()->port(); std::string name = conn->name(); conn->set_empty(false); g_thread_pool.enqueue([conn, name, ip, port]{ reconnect(conn, name, ip, port); }); }); } return *g_connector.get(); }
07-02 10:24