libuv概述
1、综述
libuv是一个高性能的,事件驱动的I/O库,支持跨平台(由平台决定使用libev或IOCP),诞生自node.js(关于node.js的介绍参见文章JavaScript介绍中node.js部分)。libev是网络库libevent的改进版,但libev在Windows下的性能不太好(使用select模型),而libuv则封装了Windows上的IOCP,性能更高,所以后来node.js使用libuv替换了libev。除了node.js以外,Rust编程语言也使用libuv。
libuv使用异步的,事件驱动的编程风格,其核心工作是提供一个event-loop,以及基于I/O等其它事件的回调通知。异步事件驱动指的是我们可以提前注册感兴趣的事件,比如读取数据,然后在数据到来可读的时候得到通知。因为是注册感兴趣的事件然后等待事件发生去处理,而不是事件处理后得到通知,所以libuv属于reactor模型。
libuv还提供了一些核心工具,如非阻塞网络支持,异步文件系统访问,定时器,子进程等。
2、安装(Windows)
从github上下载libuv项目后,可以按照readme上的提示生成对应的库文件来使用,如下所示。在build目录中生成的项目中,uv为动态库项目,uv_a为就静态库项目,比如在项目中使用libuv静态库的话,需要添加libuv的头文件目录(libuv-1.x\include)到项目中,然后添加静态库目录和静态库文件,另外还需要添加ws2_32.lib、iphlpapi.lib、userenv.lib、dbghelp.lib这些winsock通信需要的静态库依赖项。
3、简单示例
如下为开启一个loop的简单示例:
#include "uv.h" int main() { uv_loop_t* loop = (uv_loop_t*)malloc(sizeof(uv_loop_t)); //loop类型的handle uv_loop_init(loop); //初始化loop uv_run(loop, UV_RUN_DEFAULT); //启动event-loop,因为没有注册任何要监听的事件,所以会直接退出,除了UV_RUN_DEFAULT,还有UV_RUN_NOWAIT(只处理一个事件,没有事件的话会阻塞)和UV_RUN_ONCE(只处理一个事件,没有事件的话直接返回) uv_loop_close(loop); //关闭loop,回收内存 uv_fs_t t; free(loop); }
handle代表了持久性对象,相应的handle上有许多与之关联的request,如uv_loop_t、uv_idle_t、uv_tcp_t。request是短暂性对象(通常只维持在一个回调函数的时间),通常对映着handle上的一个I/O操作,用来传递上下文,如uv_fs_t、uv_req_t、uv_connect_t。handle和request都有一个void*类型的data域,可以用来存储自定义的上下文信息。
下面是一个使用空转handle(uv_idle_t)的例子,当达到1000的计数后,关闭空转监视器,当找不到活着的事件监视器后,uv_run()也会退出:
#include "uv.h" int64_t counter = 0; void wait_for_a_while(uv_idle_t* handle) { counter++; if (counter >= 1000) { uv_idle_stop(handle); printf("stop Idling\n"); } } int main() { uv_idle_t idler; //空转handle uv_loop_t* loop = uv_default_loop(); //使用libuv提供的默认loop uv_idle_init(loop, &idler); uv_idle_start(&idler, wait_for_a_while); printf("Idling start\n"); uv_run(loop, UV_RUN_DEFAULT); uv_loop_close(loop); printf("Idling end\n"); }
4、终止event loop
uv_stop(uv_loop_t*)用来终止event loop,loop会停止的最早时间点是在下次循环的时候,这也就意味着在本次循环中已经准备被处理的事件,依然会被处理。调用uv_stop()后,uv_loop_t::stop_flag域会被设置为1。