libuv 是一个跨平台的异步 I/O 库,最初为 Node.js 开发,现在也被 Luvit、Julia 和其他项目使用。它提供了一套高性能的事件驱动编程模型,抽象了不同操作系统上的非阻塞 I/O 操作,并提供了统一的 API。
完整的事件循环:基于 epoll、kqueue、IOCP、event ports 等机制
异步 TCP 和 UDP 套接字
异步 DNS 解析
异步文件和文件系统操作
文件系统事件
ANSI 转义控制的 TTY
进程间通信:支持通过 Unix domain sockets 或命名管道共享套接字
子进程管理
线程池
信号处理
高精度时钟
线程和同步原语
事件循环是 libuv 的核心,所有的 I/O 操作都在事件循环中进行。它通过以下接口管理:
uv_loop_t
:表示事件循环的结构体
uv_loop_init()
:初始化事件循环
uv_run()
:启动事件循环
uv_loop_close()
:关闭事件循环
句柄是 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
:文件系统轮询
请求是短期存在的对象,表示一次操作。所有的请求都继承自 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
:随机数生成请求
libuv 使用回调来处理异步操作的结果。通常所有异步函数都接受一个回调函数作为最后一个参数:
uv_fs_open(loop, &req, "file.txt", O_RDONLY, 0, on_open);
void on_open(uv_fs_t* req) {
// 处理打开文件的结果
}
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
#include
#include
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
#include
#include
#include
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
#include
#include
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);
}
提供异步文件 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
#include
#include
#include
#include
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);
}
提供线程创建和同步操作:
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
#include
#include
#define THREAD_COUNT 5
uv_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;
}
提供子进程的创建和管理:
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
#include
#include
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);
}
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
#include
#include
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
#include
#include
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
#include
#include
#include
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.c
文件中,提供了以下功能:
针对 NuttX 的事件循环实现
文件系统操作的适配
网络功能的适配
进程和线程功能的适配
libuv 提供了高性能、跨平台的异步 I/O 能力,是构建高性能网络服务和应用程序的理想框架。它的事件驱动模型和统一的 API 使得开发者能够更容易地编写高效的异步代码,而不必担心不同平台的底层实现差异。
在 NuttX 系统中集成 libuv,可以为实时操作系统带来强大的网络和 I/O 能力,促进更多应用程序在嵌入式设备上的开发。