异步I/O库-libuv介绍

news2024/12/26 12:06:18

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介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1679209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VC++ 6.0开发文件重复整理工具开发

开发背景&#xff1a;手机上的文件越来越多&#xff0c;想要备份下文件结果文件太多杂乱无章且重复文件冗余存储造成存储空间滥发&#xff0c;所以决定开发一个小工具来整理重复文件。由于本人电脑运行慢&#xff0c;选择VC6.0作为开发IDE&#xff0c;操作虽然麻烦点&#xff0…

【记录】docker笔记(五):Docker网络-Network Namespace

Docker 网络理论基础 要了解docker网络&#xff0c;先了解如下基础概念。 Network Namespace Docker 网络的底层原理是 Linux 的 Network Namespace &#xff0c;所以对于 Linux Network Namespace 的理解对 Docker 网络底层原理的理解非常重要。 简介 Network Name…

java技术:nacos

目录 一、docker安装 1、创建一个nacos 2、复制配置信息出来&#xff08;方便修改配置文件&#xff09; 3、删除nacos 4、修改配置文件&#xff08;主要是一下几个&#xff09; 6、创建数据库 nacos 7、重启nacos mysql 一、docker安装 1、创建一个nacos docker run …

添砖Java之路(其七)——static

目录 static&#xff1a; 1.被类的所有对象所共享(和c有点像) 2.多了一种调用方法&#xff0c;可以通过类名调用 3.随着类的加载而加载&#xff0c;是优先于对象的存在。 工具类&#xff1a; 为什么主类的方法要加static&#xff1a; 理解 public static void main&#…

你还在手动加好友?试试这款神器,释放双手自动添加!

你还在手动添加微信好友吗&#xff1f;尤其是在忙碌的时候&#xff0c;手动加好友不仅费时又很容易出错。试试这个自动添加好友神器——个微管理系统&#xff0c;释放你的双手&#xff0c;轻松拓展好友列表&#xff01; 1、多号同时登录在线 系统支持多个微信号同时登录在线&…

USB-OTG:1、OTG原理介绍

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…

运维别卷系列 - 云原生监控平台 之 05.prometheus alertManager 实践

文章目录 [toc]Alertmanager 简介Alertmanager 实现的核心概念GroupingInhibitionSilencesClient behaviorHigh Availability Alertmanager 配置文件globaltemplatesrouteinhibit_rulesreceivers Alertmanager 部署创建 cm创建 svc创建 stsPrometheus 配置告警Prometheus 配置文…

010.理解异步性

异步消息传递是响应式系统的一个关键特性。但到底是什么异步性&#xff0c;为什么它对响应式应用程序如此重要?我们的人生注定在许多异步任务中。你可能没有意识到&#xff0c;但你的日常活动如果它们本质上不是异步的&#xff0c;那就太烦人了。要理解什么是异步&#xff0c;…

评价决策类-层次分析法

师从江北 问题引出 归一化处理&#xff1a;指标的数组[a b c]归一化处理得到[a/(abc),b/(abc),c/(abc)] 因为每个指标的重要性不同&#xff0c;所以要加上一个权重 如何科学的确定权重&#xff0c;就要用到层次分析法&#xff08;AHP&#xff09; 模型原理 建立递阶层次结构模…

利用一下Chat-GPT写两段处理字符串的简单样例ABAP程序。这样可以大大提高工作效率。Chat-GPT的能力真是让人震撼。

我让Caht-GPT写两段ABAP 程序&#xff0c;第一段程序要求如下&#xff1a; 判读字符串里面是否含有特殊字符&#xff0c;这里说的特殊字符不包括键盘上能够输入的字符&#xff0c;如果有这样的特殊字符则输出来。 DATA: lv_string TYPE string VALUE 你的字符串,lv_result TYP…

数据结构——二叉树知识点详解!

引言&#xff1a;本篇博客将详细介绍到数据结构中的又一位大将——二叉树。它也是我们目前学到的第一个非线性的数据结构。并且本章将学到的概念居多&#xff0c;希望大家可以理解并牢记。 更多有关C语言和数据结构知识详解可前往个人主页&#xff1a;计信猫 目录 一&#xff0…

node.js的Express框架的介绍 与 安装详细教程

一、Express框架介绍 &#xff08;1&#xff09;Express定义&#xff1a; Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用&#xff0c;和丰富的 HTTP 工具。 使用 Express 可以快速地搭建一个完整功能的网站。 &#xff08…

微信小程序快速开发-基础内容(内容真的又多又干货)

目录 实现横向布局效果 实现滚动效果 实现轮播图效果 实现文本长按选中复制效果 渲染 HTML 标签 按钮组件的使用效果 图片组件的使用效果 Mustache 语法 动态绑定内容&#xff08;定义变量&#xff0c;渲染变量&#xff09; 动态绑定属性&#xff08;将属性定义为变量…

2024年中国国际厨卫家居展览会(上海KIB厨卫展)

中国国际厨卫家居博览会&#xff08;KIB&#xff09;由中国五金制品协会、中国国际贸易促进委员会轻工行业分会、北京奥维云网大数据科技股份有限公司主办。从最初的“中国国际橱柜、厨房卫浴产品与技术博览会(CIKB&#xff09;”&#xff0c;到2001年与中国国际五金展&#xf…

LSTM与GAN创新结合!模型性能起飞,准确率超98%

今天来聊一个深度学习领域非常具有创新性的研究方向&#xff1a;LSTM结合GAN。 LSTM擅长处理和记忆长期的时间依赖关系&#xff0c;而GAN可以学习复杂的数据分布并生成逼真的数据样本。通过充分结合两者的优势&#xff0c;我们可以增强模型对复杂数据的处理能力&#xff0c;提…

scanf读取标准输入

内容 scanf函数的原理 多种数据类型混合输入 常用的数据输入/输出函数 程序员可以给程序输入数据&#xff0c;程序处理后会返回一个输出。C语言通过函数库读取标准输入&#xff0c;然后通过对应函数处理将结果打印到屏幕上&#xff0c;printf函数可以将结果打印到屏幕上。下…

英语学习笔记14——What color‘s your ... ?

What color’s your … ? 你的 …… 是什么颜色的&#xff1f; 词汇 Vocabulary case n. 箱子【封闭的】 相关&#xff1a;box n. 箱子【开口的】    bookcase n. 书架 补充&#xff1a;case n. 案件&#xff0c;案例 口语&#xff1a;It’s a small case.    小意思&…

稚晖君独家撰文:具身智能即将为通用机器人补全最后一块拼图

具身智能新纪元。 *本文为稚晖君独家供稿,「甲子光年」经智元机器人授权发布。稚晖君本名彭志辉,先后任职OPPO、华为,现为智元机器人CTO、首席架构师。 在ChatGPT之后,又一个大模型概念火了——具身智能(Embodied AI)。 在学术界,图灵奖得主、上海期智研究院院长姚期…

【数据结构】堆(超详细)

文章目录 前言堆的概念及结构堆的实现堆的向下调整算法&#xff08;建小堆为例&#xff09;堆的向上调整算法&#xff08;建小堆为例&#xff09;堆的初始化销毁堆堆的插入堆的删除(规定删堆顶的数据)取堆顶元素判断堆是否为空获取堆的个数 完整代码&#xff08;包括测试代码&a…

解决kali Linux2024无法获取动态IPv4地址(DHCP)解决方案

用root用户启动终端 进入根目录&#xff0c;选择配置文件 cd到根目录下/../etc/network找到interfaces文件 编辑interfaces文件 vi interfaces&#xff0c;编辑interfaces文件 输入如下命令 打开虚拟网络编辑器 选择虚拟机选项卡&#xff0c;编辑&#xff0c;打开虚拟网络编…