1.简介
libuv是一个跨平台的支持事件驱动的异步I/O的库,使开发者可以以非阻塞的方式执行文件I/O操作、网络通信、子进程管理等。
libuv的主要特点包括:
- 事件循环:libuv有一个基于事件循环的模型,它不断地轮询事件,并在事件发生时调用相应的回调函数。
- 异步I/O:libuv提供了异步文件I/O和网络I/O的接口,使得开发者可以执行I/O操作而不阻塞主线程。
- 线程池:libuv使用线程池来处理一些不能以非阻塞方式执行的I/O操作,如文件系统操作在某些操作系统上。
- DNS解析:libuv提供了异步DNS解析的接口。
- 高分辨率时钟:libuv提供了高精度的时间测量接口。
libuv的使用通常涉及以下几个步骤:
- 初始化:使用uv_loop_init初始化事件循环。
- 创建句柄:根据需要创建相应的句柄,如TCP句柄、UDP句柄等。
- 启动事件循环:使用uv_run启动事件循环。
- 关闭句柄:在不再需要句柄时,使用uv_close关闭句柄。
- 清理资源:在程序结束时,使用uv_loop_close清理事件循环。
2.常用接口介绍
uv_loop_t - 事件循环
- uv_loop_init(uv_loop_t*):初始化一个事件循环。
- uv_run(uv_loop_t*,uv_run_mode):开始运行事件循环。uv_run_mode 可以是 UV_RUN_DEFAULT、UV_RUN_ONCE 或UV_RUN_NOWAIT。
- uv_loop_close(uv_loop_t*):关闭事件循环并释放相关资源。
uv_handle_t - 句柄基类
- uv_handle_size(uv_handle_type):返回特定类型句柄的大小。
- uv_close(uv_handle_t*, uv_close_cb):关闭一个句柄并释放资源。当句柄关闭完成后,会调用
uv_close_cb 回调函数。
uv_tcp_t - TCP 句柄
- uv_tcp_init(uv_loop_t*, uv_tcp_t*):初始化一个 TCP 句柄。
- uv_tcp_bind(uv_tcp_t*, const struct sockaddr*, unsigned int):将 TCP句柄绑定到指定的地址和端口。
- uv_tcp_connect(uv_connect_t*, uv_tcp_t*, const struct sockaddr*, uv_connect_cb):异步连接到服务器。连接成功或失败时会调用 uv_connect_cb 回调函数。
uv_udp_t - UDP 句柄
- uv_udp_init(uv_loop_t*, uv_udp_t*):初始化一个 UDP 句柄。
- uv_udp_bind(uv_udp_t*, const struct sockaddr*, unsigned int):将 UDP句柄绑定到指定的地址端口。
- uv_udp_recv_start(uv_udp_t*, uv_alloc_cb,uv_udp_recv_cb):开始接收 UDP 数据。uv_alloc_cb 用于分配接收缓冲区,uv_udp_recv_cb用于处理接收到的数据。
uv_timer_t - 定时器
- uv_timer_init(uv_loop_t*, uv_timer_t*):初始化一个定时器。
- uv_timer_start(uv_timer_t*, uv_timer_cb, uint64_t,uint64_t):启动定时器。uv_timer_cb 是定时器超时时的回调函数,uint64_t 参数指定第一次超时时间和重复间隔。
- uv_timer_stop(uv_timer_t*):停止定时器。
uv_work_t - 工作线程
- uv_queue_work(uv_loop_t*, uv_work_t*, uv_work_cb,
uv_after_work_cb):将工作推送到 libuv 的线程池中执行。uv_work_cb
是在线程池中执行的工作函数,uv_after_work_cb 是工作完成后在事件循环线程中调用的回调函数。
uv_process_t - 进程
- uv_spawn(uv_loop_t*, uv_process_t*, constuv_process_options_t*):创建一个新进程。
- uv_process_kill(uv_process_t*, int):发送信号到进程。
uv_fs_t - 文件系统操作
- uv_fs_open(uv_loop_t*, uv_fs_t*, const char*, int, int,uv_fs_cb):异步打开文件。
- uv_fs_read(uv_loop_t*, uv_fs_t*, uv_file, const uv_buf_t*, unsigned int, int64_t, uv_fs_cb):异步读取文件。
- uv_fs_write(uv_loop_t*, uv_fs_t*, uv_file, const uv_buf_t*, unsigned int, int64_t, uv_fs_cb):异步写入文件。
3.环境搭建
下载地址:https://github.com/libuv/libuv
下载完成,进行解压,然后使用cmake编译。
configure->Generate->Open Project
生成库如下图所示:
拷贝头文件和lib、dll目录到demo程序,然后配置visual sudio环境。具体步骤请看前面文章配置。
4.示例
TCP服务端:
#include <iostream>
#include <string>
extern "C"
{
#include "uv.h"
}
void on_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
void on_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) {
if (nread < 0) {
// 如果读取错误或连接已关闭,释放内存并关闭客户端
uv_close((uv_handle_t*)client, NULL);
free(buf->base);
return;
}
std::string message = "Hello, World!\n";
uv_write_t* req = (uv_write_t*)malloc(sizeof(uv_write_t));
uv_buf_t wrbuf = uv_buf_init((char*)message.c_str(), message.length());
uv_write(req, client, &wrbuf, 1, [](uv_write_t* req, int status) {
free(req);
if (status < 0) {
std::cerr << "Write error: " << uv_strerror(status) << std::endl;
}
});
// 释放内存
free(buf->base);
}
void on_new_connection(uv_stream_t* server, int status) {
if (status < 0) {
std::cerr << "New connection error: " << uv_strerror(status) << std::endl;
return;
}
uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
uv_tcp_init(uv_default_loop(), client);
if (uv_accept(server, (uv_stream_t*)client) == 0) {
uv_read_start((uv_stream_t*)client, on_alloc, on_read);
}
else {
uv_close((uv_handle_t*)client, NULL);
}
}
int main()
{
uv_tcp_t server;
uv_tcp_init(uv_default_loop(), &server);
struct sockaddr_in addr;
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_new_connection);
if (r) {
std::cerr << "Listen error: " << uv_strerror(r) << std::endl;
return 1;
}
std::cout << "Listening on port 8080..." << std::endl;
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
return 0;
}
TCP客户端:
void on_connect(uv_connect_t* req, int status) {
if (status < 0) {
std::cerr << "Connect error: " << uv_strerror(status) << std::endl;
return;
}
// 连接成功,发送数据
uv_stream_t* stream = req->handle;
std::string message = "Hello, Server!\n";
uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t));
uv_buf_t buf = uv_buf_init((char*)message.c_str(), message.length());
uv_write(write_req, stream, &buf, 1, [](uv_write_t* req, int status) {
free(req);
if (status < 0) {
std::cerr << "Write error: " << uv_strerror(status) << std::endl;
}
});
}
void on_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) {
if (nread < 0) {
// 如果读取错误或连接已关闭,释放内存并关闭客户端
uv_close((uv_handle_t*)client, NULL);
free(buf->base);
return;
}
// 打印接收到的数据
std::cout.write(buf->base, nread);
// 释放内存
free(buf->base);
}
int main() {
uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
uv_tcp_init(uv_default_loop(), socket);
struct sockaddr_in dest;
uv_ip4_addr("127.0.0.1", 8080, &dest);
uv_connect_t* connect_req = (uv_connect_t*)malloc(sizeof(uv_connect_t));
uv_tcp_connect(connect_req, socket, (const struct sockaddr*)&dest, on_connect);
// 开始读取数据
uv_read_start((uv_stream_t*)socket, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}, on_read);
std::cout << "Connecting to server..." << std::endl;
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
// 清理资源
free(socket);
free(connect_req);
return 0;
}
5.更多参考
libVLC 专栏介绍-CSDN博客
Qt+FFmpeg+opengl从零制作视频播放器-1.项目介绍_qt opengl视频播放器-CSDN博客
QCharts -1.概述-CSDN博客
网络库-libevent介绍
网络库-libcurl介绍