1.nodejs深入学习系列之libuv基础篇(一)
2.nodejs的http.createServer过程解析
3.网络I/O库总结(libevent,libuv,libev,libeio)
nodejs深入学习系列之libuv基础篇(一)
本文深入探讨libuv基础概念与实践,旨在帮助开发者全面理解libuv这一强大的异步IO库。首先,我们介绍了libuv的编译方式与简单使用方法,提供了入门级示例帮助开发者快速上手。
接下来,微信营销裂变源码我们深入讲解了libuv的关键概念。首先,了解了事件循环线程,这是libuv的核心机制之一,负责管理所有异步操作。接着,我们详细介绍了句柄(Handle)的概念,包括初始化、长生命周期特点以及libuv提供的各种句柄类型,如uv_timer_t、uv_idle_t、uv_prepare_t、uv_check_t、uv_async_t、磁力搜 源码uv_poll_t、uv_signal_t、uv_process_t、uv_stream_t、uv_tcp_t、uv_pipe_t、uv_tty_t、uv_udp_t、uv_fs_event_t与uv_fs_poll_t等。我们逐一解析了各句柄的用途与实现原理,并通过实例代码展示其应用。
在理解句柄的基础上,我们引入了request概念,它与句柄协同工作,用于执行特定操作,如关闭连接等。我们还附上了一张思维导图,清晰展示了libuv中句柄与request之间的关系与使用方法。
最后,android 源码 emacs我们概述了libuv的三种运行模式,强调了灵活运用这三种模式的重要性。本篇内容较为丰富,若想深入了解libuv,建议阅读后续深入学习系列文章或自行实践相关示例代码。
nodejs的.js,我们最终触及到了``模块提供的关键功能,主要关注其关键代码。
在这过程中,我们看到了`TCP`连接的处理,服务器创建一个`handle`并保存,`handle`是一个TCP对象。然后执行`bind`和`listen`操作,进入`TCP`类代码,`TCP`是C++提供的类,对应的文件是`tcp_wrap.cc`。
在`new TCP`时,实际上是执行了libuv的`uv_tcp_init`函数,初始化一个`uv_tcp_t`结构体。layoutmanager源码分析了解`uv_tcp_t`结构体后,继续查看`uv__stream_init`的操作。
从代码中,`uv__stream_init`对`uv_tcp_t`结构体执行了初始化操作,至此,`new TCP`逻辑完成。接着,分析`bind`和`listen`在Node.js中的调用逻辑,其中`bind`对应`libuv`的`uv__tcp_bind`,`listen`对应`uv_tcp_listen`。首先关注`bind`的核心代码。
一系列操作包括新建一个socket文件描述符,设置特定标志,将文件描述符保存到IO观察者中,libuv在`poll IO`阶段监听该文件描述符,当有事件发生时,执行设置的回调函数`uvstream_io`,该函数在`uvstream_init`中设置。最后执行`bind`进行绑定操作。jeecms 网站源码
接下来,解析`listen`函数。主要关注`tcp_wrapper.cc`代码,重点在于`OnConnection`函数,该函数是`listen`函数设置的回调函数,当`IO观察者`中保存的文件描述符接收到连接时,被调用。`OnConnection`函数在`connection_wrap.cc`定义,`tcp_wrapper`继承自`connection_wrap`。
在`uv_listen`函数中,调用了`uv_tcp_listen`,核心代码如下。在libuv的`poll IO`阶段,`epoll_wait`监听到连接,调用`uv__server_io`。关键代码如下。
libuv摘下连接,得到对应的socket。然后执行Node.js层的回调函数,这时分析`OnConnection`代码。
在`OnConnection`中,新建一个`uv_tcp_t`结构体,代表新连接,调用`uv_accept`获取新连接。最终执行Node.js设置的回调函数。
总结`listen`函数流程,主要步骤是设置socket为监听状态,注册事件,等待连接,连接到来时调用`accept`获取新连接,`tcp_wrapper.cc`回调新建`uv_tcp_t`结构体,代表新连接,设置可读写事件,回调为`uvstream_io`,等待数据,最后执行`net.js`设置的`onconnection`回调。
至此,服务器启动并开始接收连接的过程完成。接下来是用户数据的读写,当用户发送数据时,处理数据的函数是`uvstream_io`,后续继续解析数据读写过程。
网络I/O库总结(libevent,libuv,libev,libeio)
Libevent
Libevent 是一个基于事件驱动模型的非阻塞网络库,用于构建高速、可移植的非阻塞 IO 应用。广泛应用于 memcached、Vomit、Nylon、Netchat 等项目中,作为底层网络库,用于实现 TCP 或 HTTP 服务。Libevent 的 GitHub 源码可访问。
Libev
Libev 是由 Marc Lehmann 独立完成的,对不同系统非阻塞模型进行简单封装,解决了不同 API 之间的不兼容问题,保证程序在大多数 *nix 平台上运行。Libev 支持类 UNIX 系统的多种 I/O 多路复用模型,如 select、poll、epoll、kqueue、evports 等,但对于 Windows 的支持仅限于 select 模型,效率较低,性能不如 Libuv 封装的 IOCP。Libev 目标是修复 Libevent 的一些设计问题,如避免使用全局变量,提供更高效的事件类型管理。
Libuv
Libuv 是一个跨平台、高性能、事件驱动的异步 IO 库,用 C 语言编写,封装了不同平台底层的高性能 IO 模型,如 epoll、kqueue、IOCP、event ports,具有高度可移植性。Libuv 为 Node.js 设计,但因其高效模型逐渐被其他语言和项目采纳,用于底层库,如 Luvit、Julia、uvloop、pyuv 等。
Libevent、Libev、Libuv 比较
根据 GitHub 星标数,Libuv 的影响力最大,其次是 Libevent,Libev 关注较少。在优先级、事件循环、线程安全等方面,Libuv 更为现代,支持多种平台和 IO 模型,提供了更优的性能和功能。Libevent 和 Libev 分别针对不同平台和需求进行优化,Libev 旨在修复 Libevent 的问题。性能和可移植性方面,Libuv 优于 Libevent 和 Libev。
异步 IO 实现
目前 Linux 异步 IO 实现有原生异步 IO 和多线程模拟异步 IO 两种方式。原生异步 IO 支持特定场景,但不充分利用 Page cache;多线程模拟异步 IO 方式如 Glibc AIO、libeio、io_uring 等,提供更广泛的适用场景。