uv-cpp:基于libuv实现的C++11风格网络库

libuv是一个跨平台的的基于事件驱动的异步io库。但是他提供的功能不仅仅是io,包括进程、线程、信号、定时器、进程间通信等。libuv主要设计应用于Nodejs,由于其卓越的性能,越来越多的知名项目也使用了这一库。


libuv是一个C语言库,意味着回调函数是C语言的回调,所以直接使用libuv网络消息回调,相关对象必须是全局的或者static对象,作为一个C++开发者,这是令人难以容忍的。于是本文将要介绍的uv-cpp应运而生。
github地址:https://github.com/wlgq2/uv-cpp
uv-cpp是基于libuv实现的C++11风格网络库。接口简洁,性能优越,做过业务压测,稳定线上运行。正确使用接口情况下,未发现core dump或内存泄漏。

一.特性

1.C++11风格回调函数:非C语言函数回调,支持非静态类成员函数及lambda。
2.TCP及UDP相关类封装:TcpServer、TcpClient、TcpConnection、TcpAccept、Udp。
3.DNS和Http:DNS查询及HTTP协议支持,基于Radix Tree支持通配符等HTTP SEVER路由机制。
4.Timer及TimerWheel:定时器及时间复杂度为O(1)的心跳超时踢出机制。
5.Async:异步机制封装。相对于原生libuv async接口,优化了调用多次可能只运行一次的问题(特性)。由于libuv几乎所有api都非线程安全,建议使用writeInLoop接口代替直接write(writeInLoop会检查当前调用的线程,如果在loop线程中调用则直接write,否则把write加到loop线程中执行)。
6.libuv信号封装。
7.Packet与PacketBuffer:包与缓存,发送/接受包,用于从TCP字节流解析协议包。由ListBuffer和CycleBuffer两种实现(前者空间友好,后者时间友好)。提供默认Packet消息协议,也可实现自定义任意消息协议(参考uvnsq实现NSQ消息协议)。
8.Log日志输出接口,可绑定至自定义Log库。

二.编译

VS2017 (windows)
Codeblocks (linux)
CMake (linux)
用MinGW也可以编译通过,亲测

三.基准测试

1.ping-pong VS boost.asio 1.67

环境:Intel Core i5 8265U + debian8 + gcc8.3.0 + libuv1.30.0 + '-O2'优化

包大小1K bytes2K bytes4K bytes8K bytes
uv-cpp16138 kbyte32071 kbyte59264 kbyte123813 kbyte
boost.asio16119 kbyte31566 kbyte58322 kbyte126210 kbyte

环境:i5-8265U + 4G内存 + 4k字节ping-pong

并发数1010010005000
uv-cpp654282 kbyte591869 kbyte401500 kbyte412855 kbyte
boost.asio633818 kbyte585716 kbyte371386 kbyte382402 kbyte

2.Apache bench VS nginx 1.14.2

环境:Intel Core i5 8265U + debian8 + gcc8.3.0 + libuv1.30.0 + '-O2'
1000 并发 && 100000 次请求和nginx对比。

四.例程

十行代码实现简单echo服务

#include <iostream>
#include <uv/include/uv11.h>

int main(int argc, char** args)
{
    uv::EventLoop* loop = uv::EventLoop::DefaultLoop();
	
    uv::TcpServer server(loop);
    server.setMessageCallback([](uv::TcpConnectionPtr ptr,const char* data, ssize_t size)
    {
        ptr->write(data, size, nullptr);
    });
    //server.setTimeout(60); //heartbeat timeout.
	
    uv::SocketAddr addr("0.0.0.0", 10005, uv::SocketAddr::Ipv4);
    server.bindAndListen(addr);
    loop->run();
}

简单的http服务器,基于Radix Tree实现的路由机制,支持通配符、设置参数。

int main(int argc, char** args)
{
    uv::EventLoop loop;
    uv::http::HttpServer::SetBufferMode(uv::GlobalConfig::BufferMode::CycleBuffer);

    uv::http::HttpServer server(&loop);
	
    //example:  127.0.0.1:10010/test
    server.Get("/test",std::bind(&func1,std::placeholders::_1,std::placeholders::_2));
    
    //example:  127.0.0.1:10010/some123abc
    server.Get("/some*",std::bind(&func2, std::placeholders::_1, std::placeholders::_2));
    
    //example:  127.0.0.1:10010/value:1234
    server.Get("/value:",std::bind(&func3, std::placeholders::_1, std::placeholders::_2));
    
    //example:  127.0.0.1:10010/sum?param1=100&param2=23
    server.Get("/sum",std::bind(&func4, std::placeholders::_1, std::placeholders::_2));
    
    uv::SocketAddr addr("127.0.0.1", 10010);
    server.bindAndListen(addr);
    loop.run();
}

五.注意事项

!对于诸如uv::Timer,uv::TcpClient等对象的释放需要调用close接口并在回调函数中释放对象,否则可能会出错。
!切勿在Loop线程外创建注册该Loop下的事件相关对象(uv::TcpClient,uv::TcpServer,uv::Timer……),建议每个Loop都绑定独立线程运行。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

草上爬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值