异步I/O库-libuv介绍

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.mfbz.cn/a/629461.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

洗地机怎么挑?洗地机选购指南,2024洗地机测评选购攻略

在快节奏的生活中&#xff0c;繁琐的清洁工作往往令人头疼&#xff0c;随着洗地机的诞生&#xff0c;极大地简化了清洁的过程&#xff0c;洗地机凭借着它吸拖洗为一体的高效清洁特点&#xff0c;受到家庭和商业场所的广泛欢迎。那么&#xff0c;洗地机怎么挑&#xff0c;要注意…

速度背!24上软考网工“经典100道母题来了”!

距离软考考试的时间越来越近了&#xff0c;趁着这两周赶紧准备起来。 今天给大家整理了——网络工程师经典100道母题&#xff08;含解析&#xff09;&#xff0c;有PDF版&#xff0c;可打印&#xff0c;每天刷一点&#xff0c;考试就像遇到“老朋友”。 第一章节&#xff1a;计…

重磅!OpenAI发布GPT-4o,非常惊艳语音版ChatGPT!

5月15日凌晨&#xff0c;谷歌召开“ I/O 2024”&#xff0c;生成式AI成为本次大会的重点并发布了一系列产品和多款大模型。 其中&#xff0c;谷歌DeepMind发布了一款全新的AI 代理&#xff08;Agent&#xff09;产品Project Astra&#xff0c;可以像昨天OpenAI发布的GPT4o一样…

springsecurity项目快速搭建

自定义security的搭建 package com.sangeng.config;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;Co…

YOLOv8改进教程|加入可改变核卷积AKConv模块,效果远超DSConv!

⭐⭐ YOLOv8改进专栏|包含主干、模块、注意力机制、检测头等前沿创新 ​ ⭐⭐ 一、 论文介绍 论文链接&#xff1a;https://arxiv.org/abs/2311.11587 代码链接&#xff1a;GitHub - CV-ZhangXin/AKConv 论文速览&#xff1a;&#xff1a;AKConv是2023年11月发表的一种可变卷积…

详细分析Vue3中的reactive(附Demo)

目录 1. 基本知识2. 用法3. Demo 1. 基本知识 reactive 是一个函数&#xff0c;用于将一个普通的 JavaScript 对象转换为响应式对象 当对象的属性发生变化时&#xff0c;Vue 会自动追踪这些变化&#xff0c;并触发相应的更新 Vue2没有&#xff0c;而Vue3中有&#xff0c;为啥…

C++入门系列-赋值运算符重载

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 赋值运算符重载 运算符重载 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊函数名的函数&#xff0c;也具有其返回值类型&#xff0c;函数名字以及参…

评价决策类-层次分析法

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

百度云防护如何开启CC攻击防护

百度云防护的最重要的功能是可以CC攻击防护&#xff0c;针对CC攻击&#xff0c;百度云防护有被动的CC攻击拦截规则&#xff0c;也有主动自定义访问策略拦截。 今天百度云来教大家如何开启百度云防护的CC攻击防御功能。 1.进入防护模板功能-创建模板 2.开启CC攻击防御功能&…

ubuntu20.04 ROS 环境下使用速腾80线激光雷达

1.相关系统环境 系统版本:ubuntu 20.04 ROS版本&#xff1a;ROS1 - noetic 激光雷达型号&#xff1a;RoboSense Ruby &#xff08;更新于2024.5.14&#xff09; 2.网口配置&#xff1a; 将PC/工控机的网口配置为&#xff1a; ipv4&#xff0c;方式设置为手动 ip地址、掩码以…

半小时搞懂STM32知识点——UART

1.UART 1.1为什么要使用UART这种协议?介绍一下UART及其特点 成本低&#xff0c;硬件简单&#xff0c;数据格式灵活&#xff1b; 低速全双工异步串行通信 1.2 UART数据帧格式&#xff1f; 起始位&#xff08;1&#xff09;&#xff0b;数据位&#xff08;5-8&#xff09; 校验位…

保研机试之【execve函数】

execve 参考&#xff1a;fork&#xff08;&#xff09;函数两次返回_fork是如何返回两次的-CSDN博客 setjmp/longjmp 还有E&#xff1a;

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

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

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

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

C++语法|对象的浅拷贝和深拷贝

背景&#xff1a; 我们手写一个顺序栈&#xff0c;展开接下来的实验&#xff1a; ⭐️ this指针指向的是类在内存中的起始位置 class SeqStack { public:SqeStack(int size 10) {cout << this << "SeqStack()" << endl;pstack_ new int[size_];t…

Gemini 5.14日更新 - 推出Gemini Advance服务

收到Gemini Advance试用邀请 今天和往常一样&#xff0c;打开Gemini&#xff0c;惊喜的发现右小角一行小字&#xff1a;试用Gemini Advance。好家伙&#xff0c;OpenAI 刚推出ChatGPT 4o&#xff0c;Google立马推出Gemini Advance&#xff0c;说明国外高科技企业也是很拼的。 …

STC8增强型单片机开发【热敏电阻】

目录 一、引言 二、热敏电阻概述 三、STC8增强型单片机简介 四、基于STC8单片机的热敏电阻测温系统 五、热敏电阻测温系统的优化与扩展 提高测量精度 扩展系统功能 六、 温度计算步骤 通过ADC采样计算出热敏电阻位置的电压 通过欧姆定律计算热敏电阻的阻值 通过阻值…

【Linux】常用指令、热键与权限管理

一、常用指令 &#xff08;1&#xff09;ls 功能&#xff1a;列出指定目录下的所有子目录与文件 用法&#xff1a;ls &#xff08;选项&#xff09; &#xff08;目录或文件名&#xff09; 常用选项&#xff1a; -a&#xff1a;列出目录下的所有文件&#xff0c;包括隐藏…

fastjson1.2.68对于文件操作的分析最全

fastjson1.2.68对于文件操作的分析 前言分析复制文件写入文件读取文件分析poc拓宽场景极限环境poc优化修改再次优化poc的分析 前言 这次分析也是分析了很久&#xff0c;因为每个链子都是自己去跟着分析了的&#xff0c;然后主要是去学习了一下怎么去挖链子 分析 前面漏洞复现…

TypeScript中的泛型(Generics)

TypeScript中的泛型&#xff08;Generics&#xff09; 在前面的几篇文章中&#xff0c;我们了解了TypeScript的类、接口和基本的数据类型系统。本文将重点介绍TypeScript中的泛型&#xff0c;这是一种强大的工具&#xff0c;它允许我们创建可重用的组件&#xff0c;同时保持类…