libuv 原理_libuv学习笔记(一)

前言

学网络I/O的时候难免会碰到这样或那样的异步IO库,比如libevent、libev、libuv,看完UNP之后动手写过几个简单的小玩意,总感觉网络底层的那些函数使用起来好麻烦,一个接一个地man起来也挺费劲,于是学习这些成熟网络I/O库的想法应运而生。

初看这些库的简介感觉都差不多,原理和poll/select/epoll等都大同小异,无非是在不同平台上面封装了一层API,不过真想把他们用起来还是没那么容易的,下面就记录一下我学习libuv的一些过程。

最开始看的是libevent,顺便把前面的I/O阻塞非阻塞同步非同步等知识复习了一遍,当我看到bufferevent的时候就看不进去了。。。(菜才是原罪),正好看到这三个库的区别的一个文章,顺便摘录一点下来:

以下对比部分来自:https://blog.csdn.net/lijinqi1987/article/details/71214974

Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library)。

异步事件库本质上是提供异步事件通知(Asynchronous Event Notification,AEN)的。异步事件通知机制就是根据发生的事件,调用相应的回调函数进行处理。

事件(Event):事件是异步事件通知机制的核心,比如fd事件、超时事件、信号事件、定时器事件。有时候也称事件为事件处理器(EventHandler),这个名称更形象,因为Handler本身表示了包含处理所需数据(或数据的地址)和处理的方法(回调函数),更像是面向对象思想中的称谓。

事件循环(EventLoop):等待并分发事件。事件循环用于管理事件。

对于应用程序来说,这些只是异步事件库提供的API,封装了异步事件库跟操作系统的交互,异步事件库会选择一种操作系统提供的机制来实现某一种事件,比如利用Unix/Linux平台的epoll机制实现网络IO事件,在同时存在多种机制可以利用时,异步事件库会采用最优机制。

对比下三个库:

libevent :名气最大,应用最广泛,历史悠久的跨平台事件库;

libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好;

libuv :开发node的过程中需要一个跨平台的事件库,他们首选了libev,但又要支持Windows,故重新封装了一套,linux下用libev实现,Windows下用IOCP实现;

优先级、事件循环、线程安全维度的对比

特性

libevent

libev

libuv

优先级

激活的事件组织在优先级队列中,各类事

件默认的优先级是相同的,可以通过设置

事件的优先级使其优先被处理

也是通过优先级队列来管理激活的时间,

也可以设置事件优先级

没有优先级概念,按照固定的顺序访

问各类事件

事件循环

event_base用于管理事件

激活的事件组织在优先级队列中,各类事件默认的优先级是相同的,

可以通  过设置事件的优先级   使其优先被处理

线程安全

event_base和loop都不是线程安全的,一个event_base或loop实例只能在用户的一个线程内访问(一般是主线程),注册到event_base或者loop的event都是串行访问的,即每个执行过程中,会按照优先级顺序访问已经激活的事件,执行其回调函数。所以在仅使用一个event_base或loop的情况下,回调函数的执行不存在并行关系

代码学习过程(代码注释):

看到好像还是libuv用的人比较多,而且速度比较好,因此打算学习libuv。

大致把libuv的API和User Guide看了一遍之后感觉还是稀里糊涂,感觉还是直接看源码比较好,先把官方文档里面的例子好好熟悉一下:

这是一个简单的tcp-echo-server回射服务器:

tcp-echo-server.c:

1 #include

2 #include

3 #include

4 #include

5

6 #define DEFAULT_PORT 9877//默认端口

7 #define DEFAULT_BACKLOG 128//TCP等待连接队列最大值

8

9 uv_loop_t *loop;//loop结构指针

10 struct sockaddr_in addr;//ipv4地址结构

11

12 typedef struct{13 uv_write_t req;14 uv_buf_t buf;15 } write_req_t;16

17 void free_write_req(uv_write_t *req) {//释放资源

18 write_req_t *wr = (write_req_t*) req;19 free(wr->buf.base);20 free(wr);21 }22

23 void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {//内存分配回调函数,buff指针用于返回相应缓冲地址!!!

24 buf->base = (char*) malloc(suggested_size);//堆上创建buff

25 buf->len =suggested_size;26 }27

28 void echo_write(uv_write_t *req, int status) {//status返回write的结果

29 if(status) {30 fprintf(stderr, "Write error %s\n", uv_strerror(status));31 }32 free_write_req(req);33 }34

35 void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {//这些参数都是libuv库为回调函数传递的,其中nread表示当前读到的字节数,buff指向缓冲区

36 if (nread > 0) {37 write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t));//write_req_t这结构有点多余吧。。直接write_req_t不行么?

38 req->buf = uv_buf_init(buf->base, nread);//复制缓冲区数据(从一个到另一个)

39 uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write);//当该连接能写的时候异步调用40 //其中&req->buf指明了缓冲区的地址,1表示如果存在uv_buf_t数组,数组的元素个数41 //echo_write是uv_write_cb类型回调指针,当write完成后调用。void (*uv_write_cb)(uv_write_t* req, int status)

42 return;43 }44 if (nread < 0) {//出错

45 if (nread != UV_EOF)//UV_EOF不一定是0,具体见文档

46 fprintf(stderr, "Read error %s\n", uv_err_name(nread));47 uv_close((uv_handle_t*) client, NULL);48 }49

50 free(buf->base);//释放缓冲区

51 }52

53 void on_new_connection(uv_stream_t *server, int status) {//这里的status参数就是库传给我们的状态参数,指示当前connect的状态(是否能连接,是否出错等)

54 if (status < 0) {//<0表示出错

55 fprintf(stderr, "New connection error %s\n", uv_strerror(status));56 //error!

57 return;58 }59

60 uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));//新建uv_tcp_t进行连接

61 uv_tcp_init(loop, client);//简介之后也把这个tcp流绑定在loop上

62 if (uv_accept(server, (uv_stream_t*) client) == 0) {//连接

63 uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read);//连接完成后在event loop准备读取,这也是个异步回调64 //等到这个事件发生(能读),异步回调才会开始。65 //alloc_buffer参数这里第一次碰到,其回调函数格式为void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)66 //该函数负责为当前行为分配缓冲区,在当前事件发生之后运行,先进行缓冲区分配工作,在这个回调函数中libuv会向你提供一个suggested_size作为缓冲区大小的建议值67 //我们需要做的是在堆上分配uv_buf_t这样的数据结构,并把buf指针指向该地址!(这个理解很关键。。。应该是这样吧?:))68 //echo_read是另一个uv_read_cb类型的回调函数,会在libuv完成read之后调用(时间点重要)。

69 }70 else{71 uv_close((uv_handle_t*) client, NULL);//出现错误,关闭

72 }73 }74

75 intmain() {76 loop = uv_default_loop();//使用默认loop

77

78 uv_tcp_t server;//tcp_t结构,这是在栈上分配

79 uv_tcp_init(loop, &server);//算是把tcp绑定在了loop上面

80

81 uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr);//ip和端口直接获得sockaddr_in结构。。要是自己写要好几个函数

82

83 uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);//绑定tcp连接和地址

84 int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection);//开始监听,loop上面对于server的event监听正式开始85 //这里的几个参数才是关键:这里可以把uv_tcp_t当成uv_stream_t的子类(进行了结构体的扩展),所以这里可以使用强制类型转换绑定的流86 //on_new_connection作为一个回调函数(有固定格式,库会有参数传递),当有连接可以connect的时候进行调用,从参数来看调用时connect还没完成!

87 if(r) {88 fprintf(stderr, "Listen error %s\n", uv_strerror(r));//libuv错误处理函数

89 return 1;90 }91 return uv_run(loop, UV_RUN_DEFAULT);//开始event loop

92 }

感觉把每个函数的调用时间搞清楚,把所有参数传递的过程搞清楚libuv库也就搞清楚了。

第一次看这种这么多回调函数的代码时感觉真的是不舒服,但一步一步想通之后就感觉好多了,关键要搞清楚libuv库到底为我们提供了什么。

libuv入门 libuv个高性能的,事件驱动的I/O库,并且提供了跨平台(如windows, linux)的API。libuv的官网:http://docs.libuv.org/ git库 https://github.com/libuv/libuv首先是根据官方介绍安装libuv:1、下载源代码2、然后进行安装步骤:$ sh autogen.sh$ ./configure$ make$ make... 阅读详情

相关推荐

libuv源码剖析(): 高效队列 Queue

Introduction libuv中的高效队列是用c语言, 只使用宏定义封装而成, 据说linux内核都是这个风格的, 因为我没有读过linux内核源码, 所以开始理解这段代码还是有些困难的. libuv中使用的是双向循环队列, 际上每个节点是两个 void* 指针, 分别保存 next, prev 指针. 原理 libuv 的 queue 现了 QUEUE_NEXT, ...

Wesley's Blog 3777

Socket编程系列之6:Libuv高性能异步IO及高效网络编程

Socket编程系列初步计划:Socket编程系列之1:Linux-API网络编程入门战Socket编程系列之2:Windows-API网络编程入门战Socket编程系列之3:Libevent网络编程入门战Socket编程系列之4:Libcurl网络编程入门战Socket编程系列之5:Boost-ASIO网络编程入门战Socket编程系列之6:Libuv网络编程入门战----------------------------------------------------Socket编程系列之6:Libuv高性能异步IO及高效网络编程Libuv个高效的异步IO开发库,Linux下采取libev,Windows下独立编程现IOCP高效网络编程。我将带领大家进行Libuv小白入门知识的讲解,并亲手配置环境,跑起来个HelloWorld案例。然后进行各个方面的项目战,并深入分析原理,包括:Libuv进程开发战、网络开发战、线程开发战等。

libuv-20190410 开源跨平台事件库 最新源代码

libuv个高性能的、事件驱动的I/O库,并且提供了跨平台(如windows, linux)

Reactor

网络通信

taozhua的博客 207

libuv架构及内部原理

设计概要 libuv个跨平台支持库,原先为 NodeJS 而写。它围绕着事件驱动的异步I/O模型而设计。 这个库提供不仅仅是对不同I/O轮询机制的简单抽象,还包括: ‘句柄’和‘流’对套接字和其他体提供了高级别的抽象; 也提供了跨平台的文件I/O和线程功能,以及其他些东西。 这是份图表解释了组成libuv的不同组件和它们相关联的子系统: 句柄和请求 libuv 提供给用户使用两个抽象,与事件循环相配合: 句柄 和 请求。 句柄 表示能够在活动时执行特定作的长期存在的对象。 比方说: 个准

哦,原来你也在这里。 4194

libuv 原理_Libuv初理解

整体概念libuv个跨平台、专门写给nodejs的库,它的设计是围绕着事件驱动的异步I/O模型。在不同的I/O轮询机制上,libuv提供的不是简单抽象对象:handle和streams为sockets和其他例提供了个高级抽象。此外,libuv还提供了跨平台文件I/O和线程化功能这里有个图表,说明了构成libuv的不同部分以及它们与什么子系统相关:handles和requestlibuv给...

weixin_39702559的博客 707

Libuv 介绍(

Libevent、libev、libuv三个网络库,都是c语言现的异步事件库 libevent :名气最大,应用最广泛,历史悠久的跨平台事件库; libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好; libuv :开发node的过程中需要个跨平台的事件库,他们首选了libev,但又要支持Windows,故重新封装了套,linux下用libev现,...

qq_35886593的博客 2万+

libuv入门(

libuv是Node.js中的异步事件处理框架。它来源于libev,然而libev只能运行于Unix-like系统上,libuv则可以同时在windows和unix-like上使用。本文主要介绍在Windows下编译和使用libuv

Da Cheng Xu 的专栏 4222

libuv 原理_Nodejs libuv运行原理详解

前言这应该是Nodejs的运行原理的第7篇分享,这篇过后,短时间内不会再分享Nodejs的运行原理,会停更段时间,PS:不是不更,而是会开挖新的坑,最近有在研究RPG Maker MV,区块链,云计算,可能会更新些相关文章,或者相关教学。回到正题,异步编程的难点在于请求与响应不是按顺序发生的。以http server 为例,异步编程赋予了server 高并发的品质,而且他可以以很小的资源代价,...

weixin_39915820的博客 146

libuv 原理_[Nodejs原理] 核心库Libuv入门(Hello World篇)

Libuv是什么?1. 简介Libuv个高性能的,事件驱动的异步I/O库,它本身是由C语言编写的,具有很高的可移植性。libuv封装了不同平台底层对于异步IO模型的现,所以它还本身具备着Windows, Linux都可使用的跨平台能力。Libuv专为Node.js而设计,但是后来因为它这种事件驱动的异步IO的高效模型逐步被很多语言和项目都采纳而作为自身的底层库而使用,像 Luvit, Jul...

weixin_30639241的博客 792

libuv学习笔记):libuv编译

libuv在windows安装 libuv下载地址 https://dist.libuv.org/dist/ 环境 cmake3.9.0 qt5.7+vs2013 libuv-v1.38.0 libuv编译生成 1.cmake配置环境 2.完成后打开工程,右键INSTALL生成 3.编译结束可能遇到如下错误,将这个文件的文件编码改为UTF-8 BOM即可 4.最后将生成好的Include 和 lib拷出来 新建个Qt工程 测试libuv使用...

qq_31539927的博客 1061

[Nodejs原理] 核心库Libuv入门(Hello World篇)

Libuv是什么?1. 简介Libuv个高性能的,事件驱动的异步I/O库,它本身是由C语言编写的,具有很高的可移植性。libuv封装了不同平台底层对于异步IO模型的...

全栈者 的博客 4478

libuv 原理_Nodejs的运行原理-libuv

前言这应该是Nodejs的运行原理的第7篇分享,这篇过后,短时间内不会再分享Nodejs的运行原理,会停更段时间,PS:不是不更,而是会开挖新的坑,最近有在研究RPG Maker MV,区块链,云计算,可能会更新些相关文章,或者相关教学。回到正题,异步编程的难点在于请求与响应不是按顺序发生的。以http server 为例,异步编程赋予了server 高并发的品质,而且他可以以很小的资源代价,...

weixin_39849387的博客 177

libuv 原理_nodejs如何利用libuv现事件循环和异步

本文是根据之前在公司内部做的分享整理而成。是早期对nodejs的个认识。源码版本10.x。nodejs是什么?libuv的工作原理nodejs的工作原理nodejs如何使用libuv现事件循环和异步1 nodejs是什么?Nodejs本质上是对js功能的拓展。提供了网络、文件、dns解析、进程线程等功能。1.1 Nodejs是如何拓展js功能的?利用v8提供的接口。1.2 如何在v8新建个自...

weixin_34009282的博客 560

libuv高效编程】libuv学习超详细教程2——libuv框架初窥

libuv的设计框架,从网络I/O看,在linux(unix)平台它可以通过网络的底层epoll作为异步的I/O处理,它的中间有层抽象层uv__io_t;而在Windows平台可以通过IOCP...

杰杰的博客 7262

libuv高效编程】libuv学习超详细教程1——libuv的编译与安装

libuv个高性能的,事件驱动的I/O,并且支持多平台的网络库,接下来就手把手带你进入libuv编译安装的学习...

杰杰的博客 1万+
上一篇: 条纹噪声图片_一种视频监控图像条纹噪声的快速检测方法
下一篇: win10无法装载iso文件_win10专业版系统无法加载iso文件怎么办
weixin_39610721
博客等级 码龄9年 40粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值