[libuv] libuv学习
From:?https://www.mobibrw.com/2016/3490
libuv 是重寫(xiě)了下libev,封裝了windows和unix的差異性。
libuv的特點(diǎn)
非阻塞TCP套接字 socket?
非阻塞命名管道
UDP
定時(shí)器
子進(jìn)程 fork?
通過(guò) uv_getaddrinfo實(shí)現(xiàn)異步DNS
異步文件系統(tǒng)API uv_fs_*
高分辨率時(shí)間 uv_hrtime
正在運(yùn)行程序路徑查找 uv_exepath
線程池調(diào)度 uv_queue_work
TTY控制的ANSI轉(zhuǎn)義代碼 uv_tty_t
文件系統(tǒng)事件支持 inotify ReadDirectoryChangesW kqueue 馬上回支持 uv_fs_event_t
進(jìn)程間的IPC與套接字共享 uv_write2
事件驅(qū)動(dòng)的風(fēng)格:程序關(guān)注/發(fā)送事件,在事件來(lái)臨時(shí)給出反應(yīng)。
系統(tǒng)編程中,一般都是在處理I/O,而IO的主要障礙是網(wǎng)絡(luò)讀取,在讀取的時(shí)候是阻塞掉的。標(biāo)準(zhǔn)的解決方案是使用多線程,每一個(gè)阻塞的IO操作被分配到一個(gè)線程。當(dāng)線程block,處理器調(diào)度處理其他線程。
libuv使用了另一個(gè)方案,異步。操作系統(tǒng)提供了socket的事件,即使用socket,監(jiān)聽(tīng)socket事件即可。
libuv簡(jiǎn)單使用 創(chuàng)建一個(gè)loop,關(guān)閉loop。
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
int main()
{
uv_loop_t *loop = malloc(sizeof(uv_loop_t));
uv_loop_init(loop);
printf("hello, libuv");
uv_run(loop, UV_RUN_DEFAULT);
uv_loop_close(loop);
free(loop);
return 0;
}
如果只需要一個(gè)loop的話(huà),調(diào)用uv_default_loop就可以了。
tips:Nodejs中使用了這個(gè)loop作為主loop。
uv_loop_t *loop = uv_default_loop();
uv_run(loop, UV_RUN_DEFAULT);
uv_loop_close(loop);
Error
初始化或同步函數(shù),會(huì)在執(zhí)行失敗是返回一個(gè)負(fù)數(shù),可以通過(guò)uv_strerror、uv_err_name獲得這個(gè)錯(cuò)誤的名字和含義
I/O函數(shù)的回調(diào)函數(shù)會(huì)被傳遞一個(gè)nread參數(shù),如果nread小于0,也代表出現(xiàn)了錯(cuò)誤。
Handle & Request
libuv的工作建立在事件的監(jiān)聽(tīng)上,通常通過(guò)handle來(lái)實(shí)現(xiàn),handle中uv_TYPE_t中的type指定了handle監(jiān)聽(tīng)的事件。
在uv.h中可以找到handle和request的定義
/* Handle types. */
typedef struct uv_loop_s uv_loop_t;
typedef struct uv_handle_s uv_handle_t;
typedef struct uv_stream_s uv_stream_t;
typedef struct uv_tcp_s uv_tcp_t;
typedef struct uv_udp_s uv_udp_t;
typedef struct uv_pipe_s uv_pipe_t;
typedef struct uv_tty_s uv_tty_t;
typedef struct uv_poll_s uv_poll_t;
typedef struct uv_timer_s uv_timer_t;
typedef struct uv_prepare_s uv_prepare_t;
typedef struct uv_check_s uv_check_t;
typedef struct uv_idle_s uv_idle_t;
typedef struct uv_async_s uv_async_t;
typedef struct uv_process_s uv_process_t;
typedef struct uv_fs_event_s uv_fs_event_t;
typedef struct uv_fs_poll_s uv_fs_poll_t;
typedef struct uv_signal_s uv_signal_t;
/* Request types. */
typedef struct uv_req_s uv_req_t;
typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
typedef struct uv_getnameinfo_s uv_getnameinfo_t;
typedef struct uv_shutdown_s uv_shutdown_t;
typedef struct uv_write_s uv_write_t;
typedef struct uv_connect_s uv_connect_t;
typedef struct uv_udp_send_s uv_udp_send_t;
typedef struct uv_fs_s uv_fs_t;
typedef struct uv_work_s uv_work_t;
/* None of the above. */
typedef struct uv_cpu_info_s uv_cpu_info_t;
typedef struct uv_interface_address_s uv_interface_address_t;
typedef struct uv_dirent_s uv_dirent_t;
handle是持久化的對(duì)象。在異步操作中,相應(yīng)的handle有許多關(guān)聯(lián)的request。
request是短暫性的,通常只維持一個(gè)回調(diào)的時(shí)間,一般對(duì)應(yīng)handle的一個(gè)IO操作。request用來(lái)在初始函數(shù)和回調(diào)函數(shù)中傳遞上下文。
例如uv_udp_t代表了一個(gè)udp的socket,每一個(gè)socket的寫(xiě)入完成后,都有一個(gè)uv_udp_send_t被傳遞。
handle的設(shè)置
uv_TYPE_init(uv_loop_t*, uv_TYPE_t);
一個(gè)idle handle的使用例子 觀察下它的生命周期
#include <stdio.h>
#include <uv.h>
int counter = 0;
void wait_for(uv_idle_t * handle)
{
counter++;
if (counter > 10e6)
{
uv_idle_stop(handle);
}
}
int main()
{
uv_idle_t idler;
uv_idle_init(uv_default_loop(), &idler);
uv_idle_start(&idler, wait_for);
printf("Idle......");
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
uv_loop_close(uv_default_loop());
return 0;
}
參數(shù)傳遞
handle和request都有一個(gè)data域,用來(lái)傳遞信息。uv_loop_t也有一個(gè)相似的data域。
文件系統(tǒng)
簡(jiǎn)單的文件讀寫(xiě)是通過(guò)uv_fs_*函數(shù)族和與之相關(guān)的uv_fs_t結(jié)構(gòu)體完成的。
系統(tǒng)的文件操作是阻塞的,所以libuv在線程池中調(diào)用這些函數(shù),最后通知loop。
如果沒(méi)有指定回調(diào)函數(shù),文件操作是同步的,return libuv error code。
異步在傳入回調(diào)函數(shù)時(shí)調(diào)用,return 0。
獲得文件描述符
int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb);
關(guān)閉文件描述符
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
回調(diào)函數(shù)
void callback(uv_fs_t* req);
還有uv_fs_read uv_fs_write uv_fs_t構(gòu)成了基本的文件操作
流操作使用uv_stream_t,比基本操作方便不少
uv_read_start uv_read_stop uv_write
流操作可以很好的配合pipe使用
pipe相關(guān)函數(shù)
uv_pipe_init uv_pipe_open uv_close
文件事件
uv_fs_event_t uv_fs_event_init uv_fs_event_start
網(wǎng)絡(luò)
uv_ip4_addr ip為 0.0.0.0表示綁定所有接口 255.255.255.255是一個(gè)廣播地址,意味著數(shù)據(jù)將往所有的子網(wǎng)接口發(fā)送,端口號(hào)0表示由操作系統(tǒng)隨機(jī)分配一個(gè)端口
tcp
TCP是面向連接的字節(jié)流協(xié)議,因此基于libuv的stream實(shí)現(xiàn)
uv_tcp_t
服務(wù)器端創(chuàng)建流程
uv_tcp_init 建立tcp句柄
uv_tcp_bind 綁定
uv_listen 建立監(jiān)聽(tīng),當(dāng)有新的連接到來(lái)時(shí),激活調(diào)用回調(diào)函數(shù)
uv_accept 接收鏈接
使用stream處理數(shù)據(jù)以及與客戶(hù)端通信
客戶(hù)端
客戶(hù)端比較簡(jiǎn)單,只需要調(diào)用uv_tcp_connect
udp
UDP是不可靠連接,libuv基于uv_udp_t和uv_udp_send_t
udp的流程與tcp類(lèi)似
libuv提供了一個(gè)異步的DNS解決方案,提供了自己的getaddrinfo
配置好主機(jī)參數(shù)addrinfo后使用uv_getaddrinfo即可
調(diào)用uv_interface_addresses獲得系統(tǒng)的網(wǎng)絡(luò)信息
未完待續(xù)。
來(lái)源:http://luohaha.github.io/Chinese-uvbook/source/introduction.html
總結(jié)
以上是生活随笔為你收集整理的[libuv] libuv学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CMake 使用方法
- 下一篇: redis 的bitmap 开源包 b