C++ 基础库 co v2.0.0 正式发布 (协程库,网络编程,日志库,JSON..)

来源: 投稿
作者: idealvin
2021-05-30

github.com/idealvin/co

co 是一个优雅、高效的 C++ 基础库,支持 Linux, Windows 与 Mac 平台,它包含协程库、网络库、日志库、命令行与配置文件解析库、单元测试框架、JSON 库等基本组件。

co 遵循极简的设计理念,提供的接口都尽可能简单明了,用户可以轻松上手。co 尽量避免过度封装,引入过多的概念,以减轻用户的学习负担,如 co 提供的协程化的 socket API,与原生 socket API 形式上基本一致,熟悉 socket 编程的用户,几乎不需要增加新的学习成本,就能轻松用这些 API 写出高性能的网络程序。

详细的参考文档


首先特别强调的是,这次提供了更加详细的参考文档:

这次直接将文档放到语雀上了,它的目录编排做得不错。有现成的平台,就直接拿来用了,懒得再去折腾个人网站啥的.. 大家可以去上面留言、提建议..
 

新特性

 

SSL


co 2.0 终于支持 SSL 了,用户需要安装 openssl 1.1 以上的版本,目前已在 openssl 上测试通过,其他 SSL 库暂未测试。

推荐使用 xmake 编译,它会提示用户是否安装 openssl, libcurl, zlib 等三方库。要启用 SSL 特性,需要预定义 CO_SSL 宏,xmake 在检测到 openssl 时会自动定义这个宏。

co/so/ssl.h 中提供了协程化的 openssl 接口,不过用户很可能不会直接使用它们,因为 co 已经将 SSL 功能内嵌到 TCP 模块中,用户可以直接使用 tcp::Server 与 tcp::Client。
 

重要改进

 

协程

  • go()
    go() 支持任意带 0 个或 1 个参数的函数或类方法,以及 std::function<void()> 类型的函数对象或指针。
void f();
void g(int);
void h(int, int);
struct T {
    void f();
    void g(int);
};

T o;
std::function<void()> k(std::bind(h, 3, 7));

go(f);
go(g, 7);
go(&T::f, &o);
go(&T::g, &o, 3);
go(k);
go(&k); // The user must ensure that k is alive when the coroutine is running.
  • 协程 API
    • 增加 co::timeout() 函数,用户可以用它判断上次调用的 co::recv(), co::send() 等 I/O 函数是否超时。
    • co::coroutine_id() 函数返回一个全局唯一的 id,1.x 版本中,不同调度线程中的协程可能有相同的 id。

 

  • co::Event
    内部增加 signaled 状态,解决没有协程等待的情况下,同步信号会丢失的问题。

 

  • co::IoEvent
    1.x 版本中仅在内部使用,2.0 中公开这个类,方便用户自行将三方网络库协程化。
int recv(SSL* s, void* buf, int n, int ms) {
    CHECK(co::scheduler()) << "must be called in coroutine..";
    int r, e;
    int fd = SSL_get_fd(s);
    if (fd <0) return -1;

    do {
        ERR_clear_error();
        r = SSL_read(s, buf, n);
        if (r> 0) return r; // success
        if (r == 0) {
            DLOG << "SSL_read return 0, error: "<< SSL_get_error(s, 0);
            return 0;
        }

        e = SSL_get_error(s, r);
        if (e == SSL_ERROR_WANT_READ) {
            co::IoEvent ev(fd, co::EV_read);
            if (!ev.wait(ms)) return -1;
        } else if (e == SSL_ERROR_WANT_WRITE) {
            co::IoEvent ev(fd, co::EV_write);
            if (!ev.wait(ms)) return -1;
        } else {
            DLOG << "SSL_read return "<< r << ", error:" << e;
            return r;
        }
    } while (true);
}
  • 上面是将 openssl 中的 SSL_read() 函数协程化的例子,只需要使用 non-blocking socket,在 openssl 产生 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE 错误时,调用 co::IoEvent 的 wait() 方法,等待相应的 I/O 事件即可。

 

TCP

  • 新增 tcp::Connection 类,用于 TCP server 的实现,该类提供了 recv(), send() 等方法,用户可以直接用该类接收、发送数据,而无需关心底层是否启用了 SSL。
  • tcp::Server
void on_connection(tcp::Connection* conn);

tcp::Server s;
s.on_connection(on_connection);
s.start("0.0.0.0", 7788);                                   // no ssl
s.start("0.0.0.0", 7788, "privkey.pem", "certificate.pem"); // use ssl


tcp::Server 只需要在 start() 方法中指定 SSL private key 与证书文件,即可启用 SSL。

  • tcp::Client
bool use_ssl = false;
tcp::Client c("127.0.0.1", 7788, use_ssl);
c.connect(1000);
c.send(...);


tcp::Client 可以通过构造函数的第 3 个参数启用 SSL。
 

HTTP

  • http::Client
    co 2.0 中,http::Client 基于 libcurl 实现,要启用此特性,必须安装 libcurl,并预定义 HAS_LIBCURL 宏。还是那句话,建议用 xmake 构建,它会自动搞定这些三方依赖。
http::Client c("https://github.com");
http::Client c("http://127.0.0.1:7777");
c.get("/");
c.get("/idealvin/co");
LOG << c.response_code();
  • http::Server
    基于 tcp::Server 实现,只要在 start() 方法中带上 SSL 私钥及证书文件,就能启用 SSL。
http::Server s
s.on_req(...);
s.start("0.0.0.0", 7777);                                    // http
s.start("0.0.0.0", 7777, "privkey.pem", "certificate.pem");  // https

 

RPC


co 2.0 中,RPC 框架添加了一些新特性:

  • 支持 SSL。
  • 支持用户名与密码认证,RPC server 可以设置多个用户名、密码。
  • rpc::Server 可以添加多个 service。
  • RPC 代码生成器可以生成 RPC client 代码。

 

JSON


1.x 版本中,JSON 库仅用一个 json::Value 类表示 JSON,JSON 对象中的元素也是 json::Value,构建 JSON 对象时需要为每个元素分配内存,JSON 对象析构时,内部所有元素都要调用 json::Value 的析构函数。基于这种方式的实现,会导致频繁的内存分配及释放操作,非常影响程序性能。

co 2.0 中,将 JSON 对象构建到一块连续的内存上,程序运行稳定后,解析 JSON 几乎不需要内存分配操作,大大提高了 parsing 速度,实测可以达到 rapidjson 的两倍以上。

另外,co 2.0 用 Json 类表示 JSON 对象,json::Value 类表示 JSON 对象中的元素。json::Value 只是一个平凡类,仅包含它在 JSON 内存块中的索引位置。JSON 对象析构时,仅调用一次 Json 类的析构函数,而不会调用 json::Value 的析构函数。
 

其他

  • 修复 co/log 中的嵌套 log bug。
  • 修复一些全局静态变量相互依赖引起的 bug。
  • co/log 日志时间增加毫秒。
  • TaskSched 类重命名为 Tasked。
  • co/time.h 新增 epoch::ms() 与 epoch::us(),用于获取自 EPOCH 开始的时间。
  • co/os.h 新增 os::signal() 方法,设置信号处理函数。
  • fastring 中新增 safe_clear() 方法。
  • Json 中新增 safe_clear() 方法。
展开阅读全文
27 收藏
分享
加载中
最新评论 (2)
还在 C++11 的路过
2021-05-31 18:59
0
回复
举报
666
2021-05-30 17:36
0
回复
举报
更多评论
2 评论
27 收藏
分享
返回顶部
顶部