libuv 中文编程指南---网络

libuv中文教程.pdf libvu官方教程的中文翻译版,详细讲述了libuv各个功能模块的使用方法,适用于刚入门学习libuv的人们 立即下载

原文转自:http://www.cnblogs.com/haippy/archive/2013/03/15/2962248.html

网络

libuv 的网络接口与 BSD 套接字接口存在很大的不同, 某些事情在 libuv 下变得更简单了, 并且所有接口都是都是非阻塞的, 但是原则上还是一致的. 另外 libuv 也提供了一些工具类的函数抽象了一些让人生厌的, 重复而底层的任务,比如使用 BSD 套接字结构来建立套接字, DNS 查询, 或者其他各种参数的设置.

libuv 中在网络 I/O 中使用了 uv_tcp_t 和 uv_udp_t 两个结构体.

TCP

TCP 是一种面向连接的流式协议, 因此是基于 libuv 的流式基础架构上的.

服务器(Server)

服务器端的 sockets 处理流程如下:

  1. uv_tcp_init 初始化 TCP 监视器.
  2. uv_tcp_bind 绑定.
  3. 在指定的监视器上调用 uv_listen 来设置回调函数, 当有新的客户端连接到来时, libuv 就会调用设置的回调函数.
  4. uv_accept 接受连接.
  5. 使用 stream operations 与客户端进行通信.

以下是一个简单的 echo 服务器的例子:

复制代码
int main() {
    loop = uv_default_loop();

    uv_tcp_t server;
    uv_tcp_init(loop, &server);

    struct sockaddr_in bind_addr = uv_ip4_addr("0.0.0.0", 7000);
    uv_tcp_bind(&server, bind_addr);
    int r = uv_listen((uv_stream_t*) &server, 128, on_new_connection);
    if (r) {
        fprintf(stderr, "Listen error %s\n", uv_err_name(uv_last_error(loop)));
        return 1;
    }
    return uv_run(loop, UV_RUN_DEFAULT);
}
复制代码

你可以看到辅助函数 uv_ip4_addr 用来将人为可读的字符串类型的 IP 地址和端口号转换成 BSD 套接字 API 所需要的 struct sockaddr_in 类型的结构. 逆变换可以使用 uv_ip4_name 来完成.

对于 IPv6 来说应该使用 uv_ip6_* 形式的函数.

大部分的设置(setup)函数都是普通函数, 因为他们都是 计算密集型(CPU-bound), 直到调用了 uv_listen 我们才回到 libuv 中回调函数风格. uv_listen 的第二个参数 backlog 队列长度 – 即连接队列最大长度.

当客户端发起了新的连接时, 回调函数需要为客户端套接字设置一个监视器, 并调用 uv_accept 函数将客户端套接字与新的监视器在关联一起. 在例子中我们将从流中读取数据.

复制代码
void on_new_connection(uv_stream_t *server, int status) {
    if (status == -1) {
        // error!
        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) {
        uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read);
    }
    else {
        uv_close((uv_handle_t*) client, NULL);
    }
}
复制代码

剩余部分的函数与上一节流式例子中的代码相似, 你可以在例子程序中找到具体代码, 如果套接字不再使用记得调用 uv_close 关闭该套接字. 如果你不再接受连接, 你可以在 uv_listen的回调函数中关闭套接字.

客户端(Client)

在服务器端你需要调用 bind/listen/accept, 而在客户端你只需要调用 uv_tcp_connect. uv_tcp_connect 使用了与 uv_listen 风格相似的回调函数 uv_connect_cb 如下:

复制代码
uv_tcp_t socket;
uv_tcp_init(loop, &socket);

uv_connect_t connect;

struct sockaddr_in dest = uv_ip4_addr("127.0.0.1", 80);

uv_tcp_connect(&connect, &socket, dest, on_connect);
复制代码

建立连接后会调用 on_connect.

UDP

User Datagram Protocol 提供了无连接, 不可靠网络通信协议, 因此 libuv 并不提供流式 UDP 服务, 而是通过 uv_udp_t 结构体(用于接收)和 uv_udp_send_t 结构体(用于发送)以及相关的函数给开发人员提供了非阻塞的 UDP 服务. 所以, 真正读写 UDP 的函数与普通的流式读写非常相似.为了示范如何使用 UDP, 下面提供了一个简单的例子用来从 DHCP 获取 IP 地址. – DHCP 发现.

Note

你应该以 root 用户运行 udp-dhcp, 因为该程序使用了端口号低于 1024 的端口.

复制代码
uv_loop_t *loop;
uv_udp_t send_socket;
uv_udp_t recv_socket;

int main() {
    loop = uv_default_loop();

    uv_udp_init(loop, &recv_socket);
    struct sockaddr_in recv_addr = uv_ip4_addr("0.0.0.0", 68);
    uv_udp_bind(&recv_socket, recv_addr, 0);
    uv_udp_recv_start(&recv_socket, alloc_buffer, on_read);

    uv_udp_init(loop, &send_socket);
    uv_udp_bind(&send_socket, uv_ip4_addr("0.0.0.0", 0), 0);
    uv_udp_set_broadcast(&send_socket, 1);

    uv_udp_send_t send_req;
    uv_buf_t discover_msg = make_discover_msg(&send_req);

    struct sockaddr_in send_addr = uv_ip4_addr("255.255.255.255", 67);
    uv_udp_send(&send_req, &send_socket, &discover_msg, 1, send_addr, on_send);

    return uv_run(loop, UV_RUN_DEFAULT);
}
复制代码

0.0.0.0 地址可以绑定本机所有网口. 255.255.255.255 是广播地址, 意味着网络包可以发送给子网中所有网口, 端口 0 说明操作系统可以任意指定端口进行绑定.

首先我们在 68 号端口上设置了绑定本机所有网口的接收套接字(DHCP 客户端), 并且设置了读监视器. 然后我们利用相同的方法设置了一个用于发送消息的套接字. 并使用 uv_udp_send在 67 号端口上(DHCP 服务器)发送 广播消息.

设置广播标志也是 必要 的, 不然你会得到 EACCES 错误 [1]. 发送的具体消息与本书无关, 如果你对此感兴趣, 可以参考源码. 若出错, 则读写回调函数会收到 -1 状态码.

由于 UDP 套接字并不和特定的对等方保持连接, 所以 read 回调函数中将会收到用于标识发送者的额外信息. 如果缓冲区是由你自己的分配的, 并且不够容纳接收的数据, 则``flags`` 标志位可能是 UV_UDP_PARTIAL. 在这种情况下, 操作系统会丢弃不能容纳的数据. (这也是 UDP 为你提供的特性).

复制代码
void on_read(uv_udp_t *req, ssize_t nread, uv_buf_t buf, struct sockaddr *addr, unsigned flags) {
    if (nread == -1) {
        fprintf(stderr, "Read error %s\n", uv_err_name(uv_last_error(loop)));
        uv_close((uv_handle_t*) req, NULL);
        free(buf.base);
        return;
    }

    char sender[17] = { 0 };
    uv_ip4_name((struct sockaddr_in*) addr, sender, 16);
    fprintf(stderr, "Recv from %s\n", sender);

    // ... DHCP specific code

    free(buf.base);
    uv_udp_recv_stop(req);
}
复制代码

UDP 选项(UDP Options)

生存时间TTL(Time-to-live)

可以通过 uv_udp_set_ttl 来设置网络数据包的生存时间(TTL).

仅使用 IPv6 协议

IPv6 套接字可以同时在 IPv4 和 IPv6 协议下进行通信. 如果你只想使用 IPv6 套接字, 在调用 uv_udp_bind6 [2] 时请传递 UV_UDP_IPV6ONLY 参数.

多播(Multicast)

套接字可以使用如下函数订阅(取消订阅)一个多播组:

UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
    const char* multicast_addr, const char* interface_addr,
    uv_membership membership);

membership 取值可以是 UV_JOIN_GROUP 或 UV_LEAVE_GROUP.

多播包的本地回路是默认开启的 [3], 可以使用 uv_udp_set_multicast_loop 来开启/关闭该特性.

多播包的生存时间可以使用 uv_udp_set_multicast_ttl 来设置.

DNS 查询(Querying DNS)

libuv 提供了异步解析 DNS 的功能, 用于替代 getaddrinfo [4]. 在回调函数中, 你可以在获得的 IP 地址上执行普通的套接字操作. 让我们通过一个简单的 DNS 解析的例子来看看怎么连接 Freenode 吧:

复制代码
int main() {
    loop = uv_default_loop();

    struct addrinfo hints;
    hints.ai_family = PF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = 0;

    uv_getaddrinfo_t resolver;
    fprintf(stderr, "irc.freenode.net is... ");
    int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints);

    if (r) {
        fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(uv_last_error(loop)));
        return 1;
    }
    return uv_run(loop, UV_RUN_DEFAULT);
}
复制代码

如果 uv_getaddrinfo 返回非零, 表示在建立连接时出错, 你设置的回调函数不会被调用, 所有的参数将会在 uv_getaddrinfo 返回后被立即释放. 有关 hostname, servname 和 hints 结构体的文档可以在 getaddrinfo 帮助页面中找到.

在解析回调函数中, 你可以在 struct addrinfo(s) 结构的链表中任取一个 IP. 这个例子也演示了如何使用 uv_tcp_connect. 你在回调函数中有必要调用 uv_freeaddrinfo.

复制代码
void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) {
    if (status == -1) {
        fprintf(stderr, "getaddrinfo callback error %s\n", uv_err_name(uv_last_error(loop)));
        return;
    }

    char addr[17] = {'\0'};
    uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16);
    fprintf(stderr, "%s\n", addr);

    uv_connect_t *connect_req = (uv_connect_t*) malloc(sizeof(uv_connect_t));
    uv_tcp_t *socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
    uv_tcp_init(loop, socket);

    connect_req->data = (void*) socket;
    uv_tcp_connect(connect_req, socket, *(struct sockaddr_in*) res->ai_addr, on_connect);

    uv_freeaddrinfo(res);
}
复制代码

网络接口(Network interfaces)

系统网络接口信息可以通过调用 uv_interface_addresses 来获得, 下面的示例程序将打印出机器上所有网络接口的细节信息, 因此你可以获知网口的哪些域的信息是可以得到的, 这在你的程序启动时绑定 IP 很方便.

复制代码
#include <stdio.h>
#include <uv.h>

int main() {
    char buf[512];
    uv_interface_address_t *info;
    int count, i;

    uv_interface_addresses(&info, &count);
    i = count;

    printf("Number of interfaces: %d\n", count);
    while (i--) {
        uv_interface_address_t interface = info[i];

        printf("Name: %s\n", interface.name);
        printf("Internal? %s\n", interface.is_internal ? "Yes" : "No");
        
        if (interface.address.address4.sin_family == AF_INET) {
            uv_ip4_name(&interface.address.address4, buf, sizeof(buf));
            printf("IPv4 address: %s\n", buf);
        }
        else if (interface.address.address4.sin_family == AF_INET6) {
            uv_ip6_name(&interface.address.address6, buf, sizeof(buf));
            printf("IPv6 address: %s\n", buf);
        }

        printf("\n");
    }

    uv_free_interface_addresses(info, count);
    return 0;
}
复制代码

is_internal 对于回环接口来说为 true. 请注意如果物理网口使用了多个 IPv4/IPv6 地址, 那么它的名称将会被多次报告, 因为每个地址都会报告一次.


libuv book 中文文档 An introduction to libuv libuv book 中文文档 An introduction to libuv libuv book 中文文档 An introduction to libuv 立即下载

相关推荐

安卓app逆向破解脱壳教程

From:Hook 神器家族的 Frida 工具使用详解:https://blog.youkuaiyun.com/FlyPigYe/article/details/90258758 详解 Hook 框架 frida (信抢红包):https://www.freebuf.com/company-information/180480.html APP逆向神器之Frida【Android初级篇】:https://www.jianshu.com/p/2d755beb1c54 frida 官网文档:https://fr..

sinat_28371057的博客 2万+

在 Ubuntu on Windows 下Webpack 错误:uv_interface_addresses解决

在 Ubuntu on Windows 上 用webpack 打包 react 程序时 报出错误 ERROR in EINVAL: invalid argument, uv_interface_addresses google了一下发现是 networkInterfaces()出错,简单的解决方法是在webpack.config.js里开头增加一段代码: try { req

做最好的自己 3172

Q&A | ZStack替代VMware实问实答

ZStack替代VMware实问实答

zstack_org的博客 1801

【libuv高效编程】libuv学习超详细教程10 —— libuv stream 流句柄解读

文章目录libuv系列文章stream handle数据结构内部APIuv__stream_init()uv__read()uv__write()uv__stream_io()uv__write_callbacks()外部API参考例程代码获取 libuv系列文章 【libuv高效编程】libuv学习超详细教程1——libuv的编译与安装 【libuv高效编程】libuv学习超详细教程2—...

杰杰的博客 3100

基于eBPF的零侵入LLM智能体观测:AgentSight架构与实战

在分布式系统和云原生架构中,可观测性是保障应用稳定运行与高效排障的核心能力。其原理在于通过日志、指标和追踪三大支柱,从外部视角持续收集和分析系统状态,而非依赖应用内部埋点。这一技术价值在于能以统一、低开销的方式,理解复杂系统的内部行为,尤其在微服务、容器化及Serverless等动态环境中至关重要。应用场景广泛覆盖了性能监控、安全审计、故障诊断与根因分析。当我们将这一基础理念应用于当下快速发展的AI智能体领域时,便自然引出了对LLM智能体进行无侵入、系统级行为观测的需求。传统的应用层方案需要集成SDK,对闭

weixin_28696185的博客 324

oracle 11.2.0.3.0 client下载,oracle64位客户端 Instant Client

oracle64位 客户端安装程序,Instant Client v11.2.0.3.0(64-bit)可以用,bo客户端需要配这个的,所以装了一个,64位操作系统中、不安装Oracle-32bit客户端,方便使用PLSQL Developer(不支持64bit位Oracle客户端)安装教程安装配置instantclient下载后,解压到D:\Oracle\instantclient_11_2(特...

weixin_42573757的博客 4516

libuv学习,创建tcp服务端试例

使用libuv,可以非常方便的创建tcp服务端,基本上除了初始化,其他所有的处理都是在回调函数中处理的。可以非常轻松的实现异步读写。其中需要注意的是,uv_read_start的第二个参数,uv_alloc_cb回调函数,在每次接收到数据触发uv_read_cb回调之前都会被调用一次,用来给接收缓存做初始化,如果是每次通过malloc申请的内存,那么就要自己手动free掉,试例中就是使用的这种方式,只不过做了处理,接收的时候没有free掉,而是通过uv_buf_init函数把它又赋值给了uv_wri...

u011983700的专栏 1281

android 数据库锁的问题

最近在项目中遇到一个错误: 12-26 17:29:10.501 32592 32644 W SQLiteConnectionPool: The connection pool for database '***.db' has been unable to grant a connection to thread 1378 (thread-pool-0) with flags 0x2 for...

低调的成长 2903

Libuv编程指南

官网:http://libuv.org/ GitHub:https://github.com/libuv/libuv 中文文档:http://luohaha.github.io/Chinese-uvbook/ 一、简介 libuv是一个支持多平台的异步IO库,它主要是为了node.js而开发的,但是也可以用于Luvit, Julia, pyuv及其他软件。 libuv强制使用异步的,事件驱动的编程风格。它的核心工作是提供一个event-loop,还有基于I/O和其它事件通知的回调函数。li..

clark的专栏 1035

CZT与FFT频谱分析方法对比:从任意频带重采样到高精度频谱分析

M = 85 % 输出点数f0 = 70 Hz % 起始频率DELF = 0.4 Hz % 频率步长频率分辨率提高到0.4 Hz分析带宽聚焦在[70, 103.6]Hz更清晰地分辨出78Hz和82Hz的频率分量。

2403_88098319的博客 1860

YOLOv13必学核心:SKAttention选择性核注意力机制原理 + 实战全拆解

SKAttention的核心思想来源于人类视觉系统的一个重要特性:根据不同的视觉刺激,人眼能够自适应地调整感受野大小。SKAttention将这一生物学原理转化为深度学习中的注意力机制,通过动态选择和融合不同大小的卷积核,实现了自适应的多尺度特征提取。在人类视觉皮层中,不同的神经元具有不同大小的感受野,而且这些感受野的大小会根据视觉刺激的类型动态调整。本文将深入解析SKAttention模块的设计原理、数学基础、实现细节,以及其在YOLOv13目标检测框架中的集成应用,为读者提供全面而深入的技术理解。

FJN110的博客 97

libuv 中文编程指南(四)网络

网络 libuv 的网络接口与 BSD 套接字接口存在很大的不同, 某些事情在 libuv 下变得更简单了, 并且所有接口都是都是非阻塞的, 但是原则上还是一致的. 另外 libuv 也提供了一些工具类的函数抽象了一些让人生厌的, 重复而底层的任务,比如使用 BSD 套接字结构来建立套接字, DNS 查询, 或者其他各种参数的设置. libuv 中在网络 I/O 中使用了 uv_tcp_t 和...

weixin_33730836的博客 399

LangChain与LangGraph核心区别解析

LangChain与LangGraph是当前大语言模型(LLM)应用开发中两个紧密相关且极具影响力的开源框架。它们源于LangChain AI公司,设计哲学互补,旨在解决不同维度的LLM工程化问题,共同构成了构建复杂智能应用的强大工具集。

weixin_35774598的博客 1924

分享:libuv 中文编程指南

分享:libuv 中文编程指南 libuv 中文编程指南 http://my.oschina.net/forhappy2010/blog/116919 poste...

109

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

libuv 中文编程指南

最近看了一些有关 libuv 的东西,另外复习了一些与同步、异步、阻塞、非阻塞,异步IO(aio)的东西, 算是技术积累吧,等有时间了整理出一个完整的文档出来,希望在今后的编程中用到。 不多说了,本文是今后几篇《libuv 中文编程指南》的前言,先介绍下 libuv 究竟是干什么的吧,看看 开源中国社区收录的有关 libuv 的介绍, libuv 是 Node 的新跨平台抽象层,用

phymat.nico的专栏 8871

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

libuv 中文编程指南---Libuv 基础

原文转自:http://www.cnblogs.com/haippy/archive/2013/03/15/2962202.html libuv 采用了 异步 (asynchronous), 事件驱动 (event-driven)的编程风格, 其主要任务是为开人员提供了一套事件循环和基于I/O(或其他活动)通知的回调函数, libuv 提供了一套核心的工具集, 例如定时器, 非阻塞网络编程的

hpp24的专栏 1万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

libuv库使用

Settings->AboutSettings->Proyx。

kessity的博客 3086

Libuv中文文档之基础编程

libuv文档

wangcg123的专栏 956

libuv 中文编程指南(二)libuv 基础

Libuv 基础 libuv 采用了 异步 (asynchronous), 事件驱动 (event-driven)的编程风格, 其主要任务是为开人员提供了一套事件循环和基于I/O(或其他活动)通知的回调函数, libuv 提供了一套核心的工具集, 例如定时器, 非阻塞网络编程的支持, 异步访问文件系统, 子进程以及其他功能. 事件循环(Event loops) 在事件编程模型中, 应用程...

weixin_34362875的博客 660

探索libuv的奥秘:《uvbook》中文版开源指南

探索libuv的奥秘:《uvbook》中文版开源指南 1、项目介绍 在编程世界中,异步I/O和事件驱动模型是构建高性能服务的关键技术。《uvbook》是《An Introduction to libuv》一书的中文翻译版本,旨在帮助广大中文开发者深入理解libuv库,这个强大的跨平台抽象层为Node.js提供了底层支持。通过本书,你将能够掌握libuv的核心原理及其在实际开发中的应用。 2、项目技...

gitblog_00082的博客 539
上一篇: libuv 中文编程指南---文件系统
下一篇: windows注册表项配置客户端代理服务器
24号杀手
博客等级 码龄15年 48粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值