uv-cpp是一个基于libuv的C++封装网络库,基于本人实际项目需求开发并使用。接口较为简单易用,并对libuv一些特性做了扩展及优化。压测结果稳定、高效。暂未发现内存泄漏及崩溃等相关bug。
- 为什么需要封装libuv
截至目前,C++没有标准网络库,常见的有ACE和boost.asio。ACE较为庞大臃肿,封装复杂,个人不推荐。boost.asio是boost库的一部分,需要依赖boost的部分实现,使用asio需要在项目引入较为庞大的boost库(虽然也可以脱离boost,个人不太习惯asio的接口)。而C语言的网络库主要有libevent、libev及libuv。libuv是nodejs的底层,较为成熟。所以如果在项目需要一套轻量级,且没有太多依赖的网络组件,最好的办法,还是自己封装一套。
- uv-cpp功能简介
1.实现了C++功能的回调
首先libuv是一个C语言库,意味着回调函数是C语言的回调,所以直接使用libuv网络消息回调,相关对象必须是全局的或者static对象,这是令人难以容忍的。这里通过libuv的用户数据功能实现了C++风格的回调,回调函数可以类成员函数,或者lambda。同时封装了TcpServer及TcpClient等类,简化编程。
2.对线程安全做了优化
libuv是一个非线程安全的库,跨线程发送数据数不允许的。uv-cpp中实现了线程安全的跨线程write数据操作。基于libuv的async异步机制实现,同时在跨线程调用时候会检查当前调用线程,如果在该loop线程中则直接发送,减少了不必要的性能损耗。实现如下:
void uv::EventLoop::runInThisLoop(const std::function<void()>& func)
{
if (nullptr == func)
return;
if (isRunInLoopThread())
{
func();
return;
}
async_->runInThisLoop(func);
}
同时libuv的aysnc接口存在多次调用只执行一次的可能(特性),比如有些操作需要在回调里面释放数据,这样就会内存泄漏。uv-cpp中的Async类优化这个问题,确保每次调用一定会被执行。
3.实现了定时器及时间轮
对libuv定时器做了一层封装,并实现了一个时间复杂度O(1)的时间轮,用于检测心跳超时。
4.实现整包发送/接受协议机制
实现了ListBuffer和CycleBuffe两种缓存机制,用于解决TCP的粘包及残包。数据会重新组成完整的包数据用于读取。性能测试显示CycleBuffe会损失20%~30%的性能。
5日志接口
uv-cpp没有实现日志功能,但是保留了接口,可以注册/绑定到自定义日志库中使用。
- uv-cpp的使用
详见example文件夹:https://github.com/wlgq2/uv-cpp/tree/master/example