libuv 框架
概述
libuv 是一个跨平台的异步 I/O 库,最初为 Node.js 开发,现在也被 Luvit、Julia 和其他项目使用。它提供了一套高性能的事件驱动编程模型,抽象了不同操作系统上的非阻塞 I/O 操作,并提供了统一的 API。
主要特性
-
完整的事件循环:基于 epoll、kqueue、IOCP、event ports 等机制
-
异步 TCP 和 UDP 套接字
-
异步 DNS 解析
-
异步文件和文件系统操作
-
文件系统事件
-
ANSI 转义控制的 TTY
-
进程间通信:支持通过 Unix domain sockets 或命名管道共享套接字
-
子进程管理
-
线程池
-
信号处理
-
高精度时钟
-
线程和同步原语
核心概念
1. 事件循环 (Event Loop)
事件循环是 libuv 的核心,所有的 I/O 操作都在事件循环中进行。它通过以下接口管理:
-
uv_loop_t
:表示事件循环的结构体 -
uv_loop_init()
:初始化事件循环 -
uv_run()
:启动事件循环 -
uv_loop_close()
:关闭事件循环
2. 句柄 (Handle)
句柄是 libuv 中长期存在的对象,通常用于表示资源。所有的句柄都继承自 uv_handle_t
:
-
uv_tcp_t
:TCP 套接字 -
uv_udp_t
:UDP 套接字 -
uv_pipe_t
:命名管道 -
uv_tty_t
:终端 I/O -
uv_poll_t
:文件描述符轮询 -
uv_timer_t
:定时器 -
uv_prepare_t
、uv_check_t
、uv_idle_t
:事件循环阶段回调 -
uv_async_t
:异步回调触发器 -
uv_process_t
:子进程 -
uv_fs_event_t
:文件系统事件 -
uv_fs_poll_t
:文件系统轮询
3. 请求 (Request)
请求是短期存在的对象,表示一次操作。所有的请求都继承自 uv_req_t
:
-
uv_write_t
:写请求 -
uv_connect_t
:连接请求 -
uv_shutdown_t
:关闭请求 -
uv_udp_send_t
:UDP 发送请求 -
uv_fs_t
:文件系统请求 -
uv_getaddrinfo_t
:DNS 解析请求 -
uv_getnameinfo_t
:反向 DNS 解析请求 -
uv_work_t
:线程池工作请求 -
uv_random_t
:随机数生成请求
4. 回调机制
libuv 使用回调来处理异步操作的结果。通常所有异步函数都接受一个回调函数作为最后一个参数:
uv_fs_open(loop, &req, "file.txt", O_RDONLY, 0, on_open);void on_open(uv_fs_t* req) {// 处理打开文件的结果
}
主要模块
1. 网络操作
libuv 提供了完整的网络编程接口:
-
TCP:提供流式的、可靠的双向通信通道
-
uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle)
:-
功能:初始化TCP句柄
-
参数:
-
loop
:事件循环 -
handle
:TCP句柄指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags)
:-
功能:将句柄绑定到特定的地址和端口
-
参数:
-
handle
:TCP句柄指针 -
addr
:要绑定的地址结构体 -
flags
:额外的标志,如UV_TCP_IPV6ONLY
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)
:-
功能:在指定的流上开始监听连接
-
参数:
-
stream
:流句柄(TCP、管道等) -
backlog
:连接队列大小 -
cb
:新连接到达时的回调函数
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_connection_cb)(uv_stream_t* server, int status)
-
-
uv_accept(uv_stream_t* server, uv_stream_t* client)
:-
功能:接受传入的连接
-
参数:
-
server
:监听连接的服务器句柄 -
client
:接受连接的客户端句柄
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, uv_connect_cb cb)
:-
功能:建立到目标地址的TCP连接
-
参数:
-
req
:连接请求句柄 -
handle
:TCP句柄 -
addr
:目标地址 -
cb
:连接完成时的回调函数
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_connect_cb)(uv_connect_t* req, int status)
-
-
示例:创建 TCP 服务器
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>uv_loop_t* loop;
struct sockaddr_in addr;void on_connection(uv_stream_t* server, int status) {if (status < 0) {fprintf(stderr, "连接错误 %s\n", uv_strerror(status));return;}uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));uv_tcp_init(loop, client);if (uv_accept(server, (uv_stream_t*)client) == 0) {// 处理新客户端连接printf("新客户端已连接\n");} else {uv_close((uv_handle_t*)client, NULL);free(client);}
}int main() {loop = uv_default_loop();uv_tcp_t server;uv_tcp_init(loop, &server);uv_ip4_addr("0.0.0.0", 8080, &addr);uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);int r = uv_listen((uv_stream_t*)&server, 128, on_connection);if (r) {fprintf(stderr, "监听错误 %s\n", uv_strerror(r));return 1;}return uv_run(loop, UV_RUN_DEFAULT);
}
-
UDP:提供无连接的消息通信
-
uv_udp_init(uv_loop_t* loop, uv_udp_t* handle)
:-
功能:初始化UDP句柄
-
参数:
-
loop
:事件循环 -
handle
:UDP句柄指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags)
:-
功能:将句柄绑定到特定的地址和端口
-
参数:
-
handle
:UDP句柄指针 -
addr
:要绑定的地址结构体 -
flags
:标志位,例如:-
UV_UDP_IPV6ONLY
:仅使用IPv6 -
UV_UDP_REUSEADDR
:允许地址重用
-
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[ ], unsigned int nbufs, const struct sockaddr* addr, uv_udp_send_cb send_cb)
:-
功能:发送UDP数据包
-
参数:
-
req
:发送请求句柄 -
handle
:UDP句柄 -
bufs
:包含数据的缓冲区数组 -
nbufs
:缓冲区数组中的元素数量 -
addr
:目标地址 -
send_cb
:发送完成时的回调函数
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_udp_send_cb)(uv_udp_send_t* req, int status)
-
-
uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb)
:-
功能:开始接收UDP数据包
-
参数:
-
handle
:UDP句柄 -
alloc_cb
:分配接收缓冲区的回调函数 -
recv_cb
:接收到数据包时的回调函数
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
-
void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
-
void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
-
-
-
uv_udp_recv_stop(uv_udp_t* handle)
:-
功能:停止接收UDP数据包
-
参数:
-
handle
:UDP句柄
-
-
返回值:成功返回0,失败返回错误码
-
-
示例:UDP 服务器
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>uv_loop_t* loop;
uv_udp_t recv_socket;
struct sockaddr_in addr;void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {buf->base = (char*)malloc(suggested_size);buf->len = suggested_size;
}void on_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,const struct sockaddr* addr, unsigned flags) {if (nread > 0) {char sender[17] = {0};uv_ip4_name((const struct sockaddr_in*)addr, sender, 16);printf("收到来自 %s 的消息: %.*s\n", sender, (int)nread, buf->base);}free(buf->base);
}int main() {loop = uv_default_loop();uv_udp_init(loop, &recv_socket);uv_ip4_addr("0.0.0.0", 9000, &addr);uv_udp_bind(&recv_socket, (const struct sockaddr*)&addr, 0);uv_udp_recv_start(&recv_socket, alloc_buffer, on_recv);return uv_run(loop, UV_RUN_DEFAULT);
}
-
DNS:提供异步 DNS 解析
-
uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, const struct addrinfo* hints)
:-
功能:异步DNS解析,将主机名转换为地址
-
参数:
-
loop
:事件循环 -
req
:DNS解析请求句柄 -
getaddrinfo_cb
:解析完成时的回调函数 -
node
:要解析的主机名(如"www.example.com"),或IP地址 -
service
:服务名或端口号(如"http"或"80") -
hints
:控制解析过程的选项,包括地址族、套接字类型等
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, int status, struct addrinfo* res)
-
-
uv_getnameinfo(uv_loop_t* loop, uv_getnameinfo_t* req, uv_getnameinfo_cb getnameinfo_cb, const struct sockaddr* addr, int flags)
:-
功能:异步反向DNS解析,将地址转换为主机名
-
参数:
-
loop
:事件循环 -
req
:请求句柄 -
getnameinfo_cb
:解析完成时的回调函数 -
addr
:要解析的IP地址 -
flags
:控制解析过程的标志,如NI_NAMEREQD、NI_NUMERICHOST等
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req, int status, const char* hostname, const char* service)
-
-
uv_freeaddrinfo(struct addrinfo* ai)
:-
功能:释放由uv_getaddrinfo分配的地址信息资源
-
参数:
-
ai
:要释放的addrinfo结构体
-
-
返回值:无
-
-
示例:DNS 解析
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>uv_loop_t* loop;void on_resolved(uv_getaddrinfo_t* resolver, int status, struct addrinfo* res) {if (status < 0) {fprintf(stderr, "解析错误 %s\n", uv_strerror(status));return;}char addr[17] = {0};uv_ip4_name((struct sockaddr_in*)res->ai_addr, addr, 16);printf("域名解析结果: %s\n", addr);uv_freeaddrinfo(res);free(resolver);
}int main() {loop = uv_default_loop();struct addrinfo hints;memset(&hints, 0, sizeof(hints));hints.ai_family = AF_INET;hints.ai_socktype = SOCK_STREAM;uv_getaddrinfo_t* resolver = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t));int r = uv_getaddrinfo(loop, resolver, on_resolved, "www.example.com", "80", &hints);if (r) {fprintf(stderr, "解析请求错误 %s\n", uv_strerror(r));return 1;}return uv_run(loop, UV_RUN_DEFAULT);
}
2. 文件系统
提供异步文件 I/O 操作:
-
uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb)
:-
功能:异步打开文件
-
参数:
-
loop
:事件循环 -
req
:文件系统请求句柄 -
path
:要打开的文件路径 -
flags
:打开模式,如O_RDONLY、O_WRONLY、O_CREAT等 -
mode
:文件权限,如S_IRUSR、S_IWUSR等(创建文件时使用) -
cb
:操作完成时的回调函数,若为NULL则为同步调用
-
-
返回值:同步模式下返回文件描述符或错误码,异步模式下成功返回0,错误返回错误码
-
回调签名:
void (*uv_fs_cb)(uv_fs_t* req)
-
-
uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[ ], unsigned int nbufs, int64_t offset, uv_fs_cb cb)
:-
功能:异步读取文件内容
-
参数:
-
loop
:事件循环 -
req
:文件系统请求句柄 -
file
:文件描述符 -
bufs
:缓冲区数组,用于存储读取的数据 -
nbufs
:缓冲区数组中的元素数量 -
offset
:从文件的哪个位置开始读取,如为-1则从当前位置开始 -
cb
:操作完成时的回调函数
-
-
返回值:同步模式下返回读取的字节数或错误码,异步模式下成功返回0,错误返回错误码
-
回调访问结果:req->result 包含读取的字节数
-
-
uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[ ], unsigned int nbufs, int64_t offset, uv_fs_cb cb)
:-
功能:异步写入文件内容
-
参数:
-
loop
:事件循环 -
req
:文件系统请求句柄 -
file
:文件描述符 -
bufs
:包含要写入数据的缓冲区数组 -
nbufs
:缓冲区数组中的元素数量 -
offset
:在文件的哪个位置开始写入,如为-1则从当前位置开始 -
cb
:操作完成时的回调函数
-
-
返回值:同步模式下返回写入的字节数或错误码,异步模式下成功返回0,错误返回错误码
-
回调访问结果:req->result 包含写入的字节数
-
-
uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
:-
功能:异步关闭文件
-
参数:
-
loop
:事件循环 -
req
:文件系统请求句柄 -
file
:要关闭的文件描述符 -
cb
:操作完成时的回调函数
-
-
返回值:同步模式下成功返回0,错误返回错误码,异步模式下成功返回0,错误返回错误码
-
-
uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
:-
功能:异步删除文件
-
参数:
-
loop
:事件循环 -
req
:文件系统请求句柄 -
path
:要删除的文件路径 -
cb
:操作完成时的回调函数
-
-
返回值:同步模式下成功返回0,错误返回错误码,异步模式下成功返回0,错误返回错误码
-
-
uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
:-
功能:异步创建目录
-
参数:
-
loop
:事件循环 -
req
:文件系统请求句柄 -
path
:要创建的目录路径 -
mode
:目录权限 -
cb
:操作完成时的回调函数
-
-
返回值:同步模式下成功返回0,错误返回错误码,异步模式下成功返回0,错误返回错误码
-
-
uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
:-
功能:异步获取文件状态
-
参数:
-
loop
:事件循环 -
req
:文件系统请求句柄 -
path
:要查询的文件或目录路径 -
cb
:操作完成时的回调函数
-
-
返回值:同步模式下成功返回0,错误返回错误码,异步模式下成功返回0,错误返回错误码
-
回调访问结果:req->statbuf 包含文件状态信息
-
示例:异步读取文件
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>uv_loop_t* loop;
uv_fs_t open_req;
uv_fs_t read_req;
uv_fs_t close_req;
char buffer[1024];void on_read(uv_fs_t* req);void on_open(uv_fs_t* req) {if (req->result < 0) {fprintf(stderr, "打开文件错误: %s\n", uv_strerror(req->result));return;}// 文件打开成功,开始读取uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));uv_fs_read(loop, &read_req, req->result, &buf, 1, 0, on_read);
}void on_read(uv_fs_t* req) {if (req->result < 0) {fprintf(stderr, "读取错误: %s\n", uv_strerror(req->result));} else if (req->result == 0) {// 已读到文件末尾,关闭文件uv_fs_close(loop, &close_req, open_req.result, NULL);} else {// 成功读取一些数据printf("读取了 %ld 字节: %.*s\n", req->result, (int)req->result, buffer);// 继续读取更多内容uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));uv_fs_read(loop, &read_req, open_req.result, &buf, 1, req->off + req->result, on_read);}
}int main() {loop = uv_default_loop();// 异步打开文件uv_fs_open(loop, &open_req, "example.txt", O_RDONLY, 0, on_open);return uv_run(loop, UV_RUN_DEFAULT);
}
3. 线程操作
提供线程创建和同步操作:
-
uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg)
:-
功能:创建新线程
-
参数:
-
tid
:线程标识符,用于存储新创建的线程ID -
entry
:线程入口函数 -
arg
:传递给线程入口函数的参数
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_thread_cb)(void* arg)
-
-
uv_thread_join(uv_thread_t* tid)
:-
功能:等待指定线程结束
-
参数:
-
tid
:要等待的线程标识符
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_mutex_init(uv_mutex_t* mutex)
:-
功能:初始化互斥锁
-
参数:
-
mutex
:互斥锁指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_mutex_lock(uv_mutex_t* mutex)
:-
功能:锁定互斥锁
-
参数:
-
mutex
:要锁定的互斥锁
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_mutex_unlock(uv_mutex_t* mutex)
:-
功能:解锁互斥锁
-
参数:
-
mutex
:要解锁的互斥锁
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_mutex_destroy(uv_mutex_t* mutex)
:-
功能:销毁互斥锁
-
参数:
-
mutex
:要销毁的互斥锁
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_sem_init(uv_sem_t* sem, unsigned int value)
:-
功能:初始化信号量
-
参数:
-
sem
:信号量指针 -
value
:信号量的初始值
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_sem_post(uv_sem_t* sem)
:-
功能:增加信号量的值
-
参数:
-
sem
:信号量指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_sem_wait(uv_sem_t* sem)
:-
功能:减少信号量的值,如果信号量为0则阻塞
-
参数:
-
sem
:信号量指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_sem_destroy(uv_sem_t* sem)
:-
功能:销毁信号量
-
参数:
-
sem
:要销毁的信号量
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_cond_init(uv_cond_t* cond)
:-
功能:初始化条件变量
-
参数:
-
cond
:条件变量指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_cond_signal(uv_cond_t* cond)
:-
功能:唤醒等待条件变量的单个线程
-
参数:
-
cond
:条件变量指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_cond_broadcast(uv_cond_t* cond)
:-
功能:唤醒所有等待条件变量的线程
-
参数:
-
cond
:条件变量指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex)
:-
功能:等待条件变量被触发
-
参数:
-
cond
:条件变量指针 -
mutex
:与条件变量关联的互斥锁
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_cond_destroy(uv_cond_t* cond)
:-
功能:销毁条件变量
-
参数:
-
cond
:要销毁的条件变量
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_barrier_init(uv_barrier_t* barrier, unsigned int count)
:-
功能:初始化屏障
-
参数:
-
barrier
:屏障指针 -
count
:需要等待的线程数量
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_barrier_wait(uv_barrier_t* barrier)
:-
功能:在屏障处等待,直到所有线程都到达屏障
-
参数:
-
barrier
:屏障指针
-
-
返回值:成功时,其中一个线程返回非零值,其他线程返回0;失败返回错误码
-
-
uv_barrier_destroy(uv_barrier_t* barrier)
:-
功能:销毁屏障
-
参数:
-
barrier
:要销毁的屏障
-
-
返回值:成功返回0,失败返回错误码
-
示例:使用线程和互斥锁
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>#define THREAD_COUNT 5uv_mutex_t mutex;
int counter = 0;void thread_entry(void* arg) {int thread_id = *(int*)arg;// 使用互斥锁保护共享变量uv_mutex_lock(&mutex);counter++;printf("线程 %d: 计数器现在是 %d\n", thread_id, counter);uv_mutex_unlock(&mutex);free(arg);
}int main() {uv_thread_t threads[THREAD_COUNT];// 初始化互斥锁uv_mutex_init(&mutex);// 创建多个线程for (int i = 0; i < THREAD_COUNT; i++) {int* thread_id = (int*)malloc(sizeof(int));*thread_id = i;uv_thread_create(&threads[i], thread_entry, thread_id);}// 等待所有线程结束for (int i = 0; i < THREAD_COUNT; i++) {uv_thread_join(&threads[i]);}// 销毁互斥锁uv_mutex_destroy(&mutex);printf("最终计数器值: %d\n", counter);return 0;
}
4. 进程管理
提供子进程的创建和管理:
-
uv_spawn(uv_loop_t* loop, uv_process_t* handle, const uv_process_options_t* options)
:-
功能:创建子进程
-
参数:
-
loop
:事件循环 -
handle
:进程句柄 -
options
:进程选项,包括:-
exit_cb
:子进程退出时的回调函数 -
file
:可执行文件路径 -
args
:命令行参数数组 -
env
:环境变量 -
cwd
:工作目录 -
flags
:进程标志,如UV_PROCESS_DETACHED -
stdio_count
和stdio
:标准输入输出重定向 -
uid
和gid
:子进程的用户和组ID
-
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal)
-
-
uv_process_kill(uv_process_t* handle, int signum)
:-
功能:向子进程发送信号
-
参数:
-
handle
:进程句柄 -
signum
:要发送的信号编号,如SIGTERM、SIGKILL等
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_kill(int pid, int signum)
:-
功能:向指定PID的进程发送信号
-
参数:
-
pid
:目标进程的PID -
signum
:要发送的信号编号
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_process_get_pid(const uv_process_t* handle)
:-
功能:获取子进程的PID
-
参数:
-
handle
:进程句柄
-
-
返回值:子进程的PID
-
示例:创建子进程
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>uv_loop_t* loop;
uv_process_t child_req;
uv_process_options_t options;void on_process_exit(uv_process_t* req, int64_t exit_status, int term_signal) {printf("子进程退出,状态码: %lld, 信号: %d\n", exit_status, term_signal);uv_close((uv_handle_t*)req, NULL);
}int main() {loop = uv_default_loop();// 设置子进程的标准输入输出uv_stdio_container_t stdio[3];stdio[0].flags = UV_IGNORE; // 忽略标准输入stdio[1].flags = UV_INHERIT_FD; // 继承父进程的标准输出stdio[1].data.fd = 1;stdio[2].flags = UV_INHERIT_FD; // 继承父进程的标准错误stdio[2].data.fd = 2;// 初始化选项memset(&options, 0, sizeof(options));options.exit_cb = on_process_exit;options.file = "/bin/hello";options.args = (char*[]){"/bin/hello", NULL}; // 需要设置参数数组options.flags = 0;options.stdio = stdio;options.stdio_count = 3;int r = uv_spawn(loop, &child_req, &options);if (r) {fprintf(stderr, "生成子进程错误 %s\n", uv_strerror(r));return 1;} else {printf("启动了 PID %d 的进程\n", child_req.pid);}return uv_run(loop, UV_RUN_DEFAULT);
}
5. 定时器和事件
-
uv_timer_init(uv_loop_t* loop, uv_timer_t* handle)
:-
功能:初始化定时器句柄
-
参数:
-
loop
:事件循环 -
handle
:定时器句柄指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
:-
功能:启动定时器
-
参数:
-
handle
:定时器句柄 -
cb
:定时器到期时的回调函数 -
timeout
:首次触发的延迟时间(毫秒) -
repeat
:重复间隔(毫秒),0表示不重复
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_timer_cb)(uv_timer_t* handle)
-
-
uv_timer_stop(uv_timer_t* handle)
:-
功能:停止定时器
-
参数:
-
handle
:定时器句柄
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_timer_again(uv_timer_t* handle)
:-
功能:重新启动定时器
-
参数:
-
handle
:定时器句柄
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat)
:-
功能:设置定时器的重复间隔
-
参数:
-
handle
:定时器句柄 -
repeat
:重复间隔(毫秒)
-
-
返回值:无
-
-
uv_timer_get_repeat(const uv_timer_t* handle)
:-
功能:获取定时器的重复间隔
-
参数:
-
handle
:定时器句柄
-
-
返回值:重复间隔(毫秒)
-
-
uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle)
:-
功能:初始化文件系统事件监视器
-
参数:
-
loop
:事件循环 -
handle
:文件系统事件句柄指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags)
:-
功能:开始监视文件或目录的变化
-
参数:
-
handle
:文件系统事件句柄 -
cb
:事件发生时的回调函数 -
path
:要监视的文件或目录路径 -
flags
:监视选项,可以是以下值的组合:-
UV_FS_EVENT_WATCH_ENTRY
:只监视目录条目本身的变化 -
UV_FS_EVENT_STAT
:使用stat轮询来监视(网络文件系统) -
UV_FS_EVENT_RECURSIVE
:递归监视子目录
-
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status)
-
事件类型:
-
UV_RENAME
:文件被重命名 -
UV_CHANGE
:文件内容或属性被修改
-
-
-
uv_fs_event_stop(uv_fs_event_t* handle)
:-
功能:停止监视文件系统事件
-
参数:
-
handle
:文件系统事件句柄
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_signal_init(uv_loop_t* loop, uv_signal_t* handle)
:-
功能:初始化信号处理器
-
参数:
-
loop
:事件循环 -
handle
:信号句柄指针
-
-
返回值:成功返回0,失败返回错误码
-
-
uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum)
:-
功能:开始监听特定信号
-
参数:
-
handle
:信号句柄 -
signal_cb
:信号到达时的回调函数 -
signum
:要监听的信号编号,如SIGINT、SIGTERM等
-
-
返回值:成功返回0,失败返回错误码
-
回调签名:
void (*uv_signal_cb)(uv_signal_t* handle, int signum)
-
-
uv_signal_stop(uv_signal_t* handle)
:-
功能:停止监听信号
-
参数:
-
handle
:信号句柄
-
-
返回值:成功返回0,失败返回错误码
-
示例:使用定时器
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>uv_loop_t* loop;
uv_timer_t timer;
int counter = 0;void timer_cb(uv_timer_t* handle) {counter++;printf("定时器回调: %d\n", counter);if (counter >= 5) {// 5次后停止定时器uv_timer_stop(handle);printf("定时器已停止\n");}
}int main() {loop = uv_default_loop();// 初始化定时器uv_timer_init(loop, &timer);// 启动定时器:1秒后开始,每隔1秒触发一次uv_timer_start(&timer, timer_cb, 1000, 1000);return uv_run(loop, UV_RUN_DEFAULT);
}
示例:文件系统事件监控(需要打开系统 FS_NOTIFY 功能)
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>uv_loop_t* loop;
uv_fs_event_t fs_event;void fs_event_cb(uv_fs_event_t* handle, const char* filename, int events, int status) {if (status < 0) {fprintf(stderr, "文件系统事件错误: %s\n", uv_strerror(status));return;}if (events & UV_RENAME) {printf("文件 %s 被重命名\n", filename ? filename : "未知");}if (events & UV_CHANGE) {printf("文件 %s 被修改\n", filename ? filename : "未知");}
}int main() {loop = uv_default_loop();// 初始化文件系统事件监控uv_fs_event_init(loop, &fs_event);// 开始监控目录int r = uv_fs_event_start(&fs_event, fs_event_cb, "/tmp", 0);if (r) {fprintf(stderr, "监控错误: %s\n", uv_strerror(r));return 1;}return uv_run(loop, UV_RUN_DEFAULT);
}
示例:信号处理
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>uv_loop_t* loop;
uv_signal_t sig_int;
uv_signal_t sig_term;void signal_handler(uv_signal_t* handle, int signum) {printf("收到信号: %d (%s)\n", signum, signum == SIGINT ? "SIGINT" : "SIGTERM");// 处理完后停止监听uv_signal_stop(handle);// 如果所有信号处理器都停止了,就可以退出循环if (!uv_is_active((uv_handle_t*)&sig_int) && !uv_is_active((uv_handle_t*)&sig_term)) {printf("所有信号处理器都已停止,退出中...\n");uv_stop(loop);}
}int main() {loop = uv_default_loop();// 初始化信号处理器uv_signal_init(loop, &sig_int);uv_signal_init(loop, &sig_term);// 开始监听 SIGINT 和 SIGTERM 信号uv_signal_start(&sig_int, signal_handler, SIGINT);uv_signal_start(&sig_term, signal_handler, SIGTERM);printf("按 Ctrl+C 发送 SIGINT 信号\n");return uv_run(loop, UV_RUN_DEFAULT);
}
NuttX 与 libuv 集成
在 NuttX 系统中,libuv 通过适配层集成,主要实现在 nuttx.c
文件中,提供了以下功能:
-
针对 NuttX 的事件循环实现
-
文件系统操作的适配
-
网络功能的适配
-
进程和线程功能的适配
结论
libuv 提供了高性能、跨平台的异步 I/O 能力,是构建高性能网络服务和应用程序的理想框架。它的事件驱动模型和统一的 API 使得开发者能够更容易地编写高效的异步代码,而不必担心不同平台的底层实现差异。
在 NuttX 系统中集成 libuv,可以为实时操作系统带来强大的网络和 I/O 能力,促进更多应用程序在嵌入式设备上的开发。