[libuv] libuv学习
From:?https://www.mobibrw.com/2016/3490
libuv 是重寫了下libev,封裝了windows和unix的差異性。
libuv的特點
非阻塞TCP套接字 socket?
非阻塞命名管道
UDP
定時器
子進程 fork?
通過 uv_getaddrinfo實現異步DNS
異步文件系統API uv_fs_*
高分辨率時間 uv_hrtime
正在運行程序路徑查找 uv_exepath
線程池調度 uv_queue_work
TTY控制的ANSI轉義代碼 uv_tty_t
文件系統事件支持 inotify ReadDirectoryChangesW kqueue 馬上回支持 uv_fs_event_t
進程間的IPC與套接字共享 uv_write2
事件驅動的風格:程序關注/發送事件,在事件來臨時給出反應。
系統編程中,一般都是在處理I/O,而IO的主要障礙是網絡讀取,在讀取的時候是阻塞掉的。標準的解決方案是使用多線程,每一個阻塞的IO操作被分配到一個線程。當線程block,處理器調度處理其他線程。
libuv使用了另一個方案,異步。操作系統提供了socket的事件,即使用socket,監聽socket事件即可。
libuv簡單使用 創建一個loop,關閉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;
}
如果只需要一個loop的話,調用uv_default_loop就可以了。
tips:Nodejs中使用了這個loop作為主loop。
uv_loop_t *loop = uv_default_loop();
uv_run(loop, UV_RUN_DEFAULT);
uv_loop_close(loop);
Error
初始化或同步函數,會在執行失敗是返回一個負數,可以通過uv_strerror、uv_err_name獲得這個錯誤的名字和含義
I/O函數的回調函數會被傳遞一個nread參數,如果nread小于0,也代表出現了錯誤。
Handle & Request
libuv的工作建立在事件的監聽上,通常通過handle來實現,handle中uv_TYPE_t中的type指定了handle監聽的事件。
在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是持久化的對象。在異步操作中,相應的handle有許多關聯的request。
request是短暫性的,通常只維持一個回調的時間,一般對應handle的一個IO操作。request用來在初始函數和回調函數中傳遞上下文。
例如uv_udp_t代表了一個udp的socket,每一個socket的寫入完成后,都有一個uv_udp_send_t被傳遞。
handle的設置
uv_TYPE_init(uv_loop_t*, uv_TYPE_t);
一個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;
}
參數傳遞
handle和request都有一個data域,用來傳遞信息。uv_loop_t也有一個相似的data域。
文件系統
簡單的文件讀寫是通過uv_fs_*函數族和與之相關的uv_fs_t結構體完成的。
系統的文件操作是阻塞的,所以libuv在線程池中調用這些函數,最后通知loop。
如果沒有指定回調函數,文件操作是同步的,return libuv error code。
異步在傳入回調函數時調用,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);
關閉文件描述符
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
回調函數
void callback(uv_fs_t* req);
還有uv_fs_read uv_fs_write uv_fs_t構成了基本的文件操作
流操作使用uv_stream_t,比基本操作方便不少
uv_read_start uv_read_stop uv_write
流操作可以很好的配合pipe使用
pipe相關函數
uv_pipe_init uv_pipe_open uv_close
文件事件
uv_fs_event_t uv_fs_event_init uv_fs_event_start
網絡
uv_ip4_addr ip為 0.0.0.0表示綁定所有接口 255.255.255.255是一個廣播地址,意味著數據將往所有的子網接口發送,端口號0表示由操作系統隨機分配一個端口
tcp
TCP是面向連接的字節流協議,因此基于libuv的stream實現
uv_tcp_t
服務器端創建流程
uv_tcp_init 建立tcp句柄
uv_tcp_bind 綁定
uv_listen 建立監聽,當有新的連接到來時,激活調用回調函數
uv_accept 接收鏈接
使用stream處理數據以及與客戶端通信
客戶端
客戶端比較簡單,只需要調用uv_tcp_connect
udp
UDP是不可靠連接,libuv基于uv_udp_t和uv_udp_send_t
udp的流程與tcp類似
libuv提供了一個異步的DNS解決方案,提供了自己的getaddrinfo
配置好主機參數addrinfo后使用uv_getaddrinfo即可
調用uv_interface_addresses獲得系統的網絡信息
未完待續。
來源:http://luohaha.github.io/Chinese-uvbook/source/introduction.html
總結
以上是生活随笔為你收集整理的[libuv] libuv学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CMake 使用方法
- 下一篇: redis 的bitmap 开源包 b