背景
新的c++11标准出后,c++语法得到了很多的扩展,比起以往任何时候都要灵活和高效,提高了程序编码的效率,为软件开发人员节省了不少的时间。 之前我也写过基于ACE的网络服务器框架,但ACE毕竟有些臃肿,内部对象关系错综复杂,容易给人造成只见树木不见森林的错觉。 所以打算用c++11开发一个较为简洁,高效,支持高并发的网络库。
开源
基础的结构已经开发完成,代码也开源在github上,网址是 https://github.com/lichuan/fly 欢迎各位提出建议。
结构
fly网络库主要分为base模块,task模块,net模块。base主要是一些最基础的功能集合,包括日志,id分配器,随机数,队列等;task主要封装了任务抽象以及任务调度执行等功能;net主要是实现网络层面的封装,为上层使用者提供简单易用的网络接口,这也是fly库的核心模块,实现了解析协议的Parser封装,负责监听网络的Acceptor,负责网络连接io功能的Poller封装体,在Parser、Acceptor、和Poller的基础上还进一步封装了作为服务器来使用的Server类和作为客户端来使用的Client类,这两个类是fly库的核心类,上层的应用可以直接使用Server对象和Client对象来建立网络服务器。作为网络连接概念的Connection对象则是通过std::shared_ptr来管理它的生命周期的,shared_ptr内置共享对象的功能大大地简化了网络连接生命期的管理。
协议
fly库的网络协议基于全世界最通用的json格式,而它的解析则依赖于rapidjson第三方库来完成。
协议组成如下:
|长度字段|{协议类型:类型值,协议命令:命令值,其他json字段}|
协议类型和协议命令组成了二级消息字,就可以组合出各种约定的协议了。
应用
fly库的test目录提供了一个简单的例程。其中test_server.cpp代码如下:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* _______ _ *
* ( ____ \ ( \ |\ /| *
* | ( \/ | ( ( \ / ) *
* | (__ | | \ (_) / *
* | __) | | \ / *
* | ( | | ) ( *
* | ) | (____/\ | | *
* |/ (_______/ \_/ *
* *
* *
* fly is an awesome c++11 network library. *
* *
* @author: lichuan *
* @qq: 308831759 *
* @email: [email protected] *
* @github: https://github.com/lichuan/fly *
* @date: 2015-06-10 13:34:21 *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include
#include
#include "fly/init.hpp"
#include "fly/net/server.hpp"
#include "fly/base/logger.hpp"
using namespace std::placeholders;
class Test_Server : public fly::base::Singleton
{
public:
bool allow(std::shared_ptr connection)
{
return true;
}
void init(std::shared_ptr connection)
{
std::lock_guard guard(m_mutex);
m_connections[connection->id()] = connection;
LOG_INFO("connection count: %u", m_connections.size());
}
void dispatch(std::unique_ptr message)
{
std::shared_ptr connection = message->get_connection();
const fly::net::Addr &addr = connection->peer_addr();
LOG_INFO("recv message from %s:%d raw_data: %s", addr.m_host.c_str(), addr.m_port, message->raw_data().c_str());
}
void close(std::shared_ptr connection)
{
LOG_INFO("close connection from %s:%d", connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
std::lock_guard guard(m_mutex);
m_connections.erase(connection->id());
LOG_INFO("connection count: %u", m_connections.size());
}
void be_closed(std::shared_ptr connection)
{
LOG_INFO("connection from %s:%d be closed", connection->peer_addr().m_host.c_str(), connection->peer_addr().m_port);
std::lock_guard guard(m_mutex);
m_connections.erase(connection->id());
LOG_INFO("connection count: %u", m_connections.size());
}
void main()
{
//init library
fly::init();
//init logger
fly::base::Logger::instance()->init(fly::base::DEBUG, "server", "./log/");
//test tcp server
std::unique_ptr server(new fly::net::Server(fly::net::Addr("127.0.0.1", 8899),
std::bind(&Test_Server::allow, this, _1),
std::bind(&Test_Server::init, this, _1),
std::bind(&Test_Server::dispatch, this, _1),
std::bind(&Test_Server::close, this, _1),
std::bind(&Test_Server::be_closed, this, _1)));
if(server->start())
{
LOG_INFO("start server ok!");
server->wait();
}
else
{
LOG_ERROR("start server failed");
}
}
private:
std::unordered_map> m_connections;
std::mutex m_mutex;
};
int main()
{
Test_Server::instance()->main();
}
Server对象构造时会要求传入监听地址和回调函数,当Server对象start启动时,fly库底层就会建立相应的Poller、Parser、Acceptor对象,如果想实现多线程Poller和Parser,则需传入并发线程数量即可,回调函数说明如下:
allow_cb:当有新的连接到达时调用,来判断是否允许该连接的注册。
init_cb:当把连接对象注册到某一个Poller和Parser后调用,进行初始化处理。
dispatch_cb:当有消息到达时会调用,进行消息派发。
close_cb:主动关闭连接对象时调用。
be_closed_cb:检测到对端关闭连接对象时调用。
test_client.cpp主要使用Client对象来连接到某一个服务器,同样Client构造时也需要传入回调函数,其作用与Server构造时传入的回调一样。