libuv学习-udp传输

本文详细介绍了使用libuv库实现的UDP服务器和客户端示例,展示了如何创建、绑定、发送和接收UDP数据包,同时解析了uv_udp_t、uv_buf_t等关键数据结构和相关函数的用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. udp传输的例子

1. udp 服务器的例子

/*
 libuv udp server
*/
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>

void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
    // Allocate a buffer for receiving data
    buf->base = (char*)malloc(suggested_size);
    buf->len = suggested_size;
}

void on_recv_data(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
    if (nread < 0) {
        // Error occurred while receiving data
        fprintf(stderr, "Error: %s\n", uv_strerror(nread));
        free(buf->base);
        return;
    }

    if (nread > 0) {
        // Process the received data
        printf("Received data: %s\n", buf->base);
    }

    free(buf->base);
}

int main() {
    uv_loop_t* loop = uv_default_loop();

    uv_udp_t server;
    uv_udp_init(loop, &server);

    struct sockaddr_in addr;
    uv_ip4_addr("0.0.0.0", 12345, &addr);

    uv_udp_bind(&server, (const struct sockaddr*)&addr, UV_UDP_REUSEADDR);

    uv_udp_recv_start(&server, on_alloc_buffer, on_recv_data);

    return uv_run(loop, UV_RUN_DEFAULT);
}

在这里插入图片描述

2. udp 客户端的例子

/*
    libuv udp client
*/
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
int main() {
    uv_loop_t* loop = uv_default_loop();

    uv_udp_t socket;
    uv_udp_init(loop, &socket);

    uv_udp_send_t send_req;
    uv_buf_t buffer;
    const char* message = "Hello, server!";
    buffer = uv_buf_init(const_cast<char*>(message), strlen(message));

    struct sockaddr_in server_addr;
    uv_ip4_addr("127.0.0.1", 12345, &server_addr);

    uv_udp_send(&send_req, &socket, &buffer, 1, (const struct sockaddr*)&server_addr, nullptr);

    uv_run(loop, UV_RUN_DEFAULT);

    uv_loop_close(loop);
    return 0;
}

在这里插入图片描述

3. nc命令模拟udp client

在这里插入图片描述

二. 代码解析

结构体解析

uv_udp_t

struct uv_udp_s {
  UV_HANDLE_FIELDS
  /* read-only */
  /*
   * Number of bytes queued for sending. This field strictly shows how much
   * information is currently queued.
   */
  size_t send_queue_size;
  /*
   * Number of send requests currently in the queue awaiting to be processed.
   */
  size_t send_queue_count;
  UV_UDP_PRIVATE_FIELDS
};
typedef struct uv_udp_s uv_udp_t;

uv_udp_t 结构体 是用于UDP通信的抽象数据类型。它代表了一个UDP套接字,用于在网络上发送和接收UDP数据包。
uv_udp_t 结构体包含了一系列用于配置和管理UDP套接字的成员变量,以及一系列用于操作UDP套接字的函数。

uv_buf_t

typedef struct uv_buf_t {
  char* base;
  size_t len;
} uv_buf_t;

uv_buf_t 结构体表示一个用于存储数据的缓冲区,通常用于在异步 I/O 操作中传递数据。
包含两个变量:
base:指向存储数据的缓冲区的起始位置的指针。
len:表示缓冲区的长度,即缓冲区中可用于存储数据的字节数。

uv_udp_send_t

struct uv_udp_send_s {
  UV_REQ_FIELDS
  uv_udp_t* handle;
  uv_udp_send_cb cb;
  UV_UDP_SEND_PRIVATE_FIELDS
};
typedef struct uv_udp_send_s uv_udp_send_t;

uv_udp_send_t 结构体代表了一个 UDP 发送请求,用于发送 UDP 数据包。它被用于异步地发送 UDP 数据包到目标地址。

函数解析

uv_udp_init

int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle);
这个函数用于初始化 UDP 套接字,并将其与事件循环关联。
在调用这个函数之后,handle 参数所指向的 uv_udp_t 结构体实例将被初始化,并且可以用于进行 UDP 相关的操作。

uv_ip4_addr

int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr);
这个函数将 IPv4 地址和端口转换为网络字节顺序,并填充到 sockaddr_in 结构体中。

形参解析:
ip:一个字符串,表示 IPv4 地址。可以是点分十进制格式的 IP 地址,也可以是域名(例如:“127.0.0.1” 或 “localhost”)。
port:一个整数,表示端口号。
addr:一个指向 sockaddr_in 结构体的指针,用于存储转换后的 IPv4 地址和端口信息。

uv_udp_bind

int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags);

这个函数是将一个 UDP 套接字绑定到指定的本地地址和端口,以便可以接收和发送数据。

形参解析:
handle:一个指向已初始化的 uv_udp_t 结构体实例的指针,表示要绑定的 UDP 套接字。
addr:一个指向 sockaddr 结构体的指针,表示要绑定的本地地址和端口。
flags:用于指定绑定选项的标志uv_udp_flags

uv_udp_recv_start

int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb);

这个函数用于通知 libuv 开始监听指定 UDP 套接字上的数据包,并指定一个回调函数来处理接收到的数据。

形参解析:
handle:一个指向已初始化的 uv_udp_t 结构体实例的指针,表示要开始接收数据的 UDP 套接字。
alloc_cb:一个回调函数,用于分配内存以存储接收到的数据。它的原型为 void (alloc_cb)(uv_handle_t handle, size_t suggested_size, uv_buf_t* buf)。
recv_cb:一个回调函数,用于处理接收到的数据。它的原型为 void (recv_cb)(uv_udp_t handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)。

uv_udp_send

int 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);

这个函数将数据包异步发送到指定的目标地址。
形参解析:
req:一个指向 uv_udp_send_t 结构体实例的指针,表示发送请求。在发送完成后,该结构体将被 libuv 使用来通知发送结果。
handle:一个指向已初始化的 uv_udp_t 结构体实例的指针,表示要使用的 UDP 套接字。
bufs:一个指向 uv_buf_t 结构体数组的指针,表示要发送的数据。每个 uv_buf_t 结构体表示一个数据缓冲区,可以包含一部分要发送的数据。
nbufs:一个无符号整数,表示 bufs 数组中数据缓冲区的数量。
addr:一个指向 sockaddr 结构体的指针,表示要发送数据的目标地址。
send_cb:一个回调函数,用于处理发送结果。它的原型为 void (send_cb)(uv_udp_send_t req, int status)

参考

libuv官方文档

https://libuv-docs-chinese.readthedocs.io/zh/latest/

chatgpt

https://chat.openai.com/
### 关于 libuv 库 #### 简介 libuv 是一个多平台支持库,具有事件驱动的核心特性。该库提供了异步 I/O 功能,并被设计用于支撑像 Node.js 这样的应用程序框架[^1]。 #### 获取和安装 为了获取 libuv 的最新版本以及其源代码,建议访问项目的官方 GitHub 仓库下载所需文件。对于大多数 Unix-like 系统(包括 Linux 和 macOS),可以按照如下方式进行编译安装: ```bash git clone https://github.com/libuv/libuv.git cd libuv sh autogen.sh ./configure make sudo make install ``` Windows 用户则可能更倾向于通过预构建二进制包或者借助工具如 vcpkg 来简化这个过程[^3]。 #### 使用方法概览 当开发者准备利用 libuv 开发时,通常会围绕 `uv_loop_t` 数据结构展开工作;这是整个事件循环的基础组件,在每次调用 `uv_run()` 函数期间都会执行一次完整的迭代以处理待办事项列表上的任务并触发相应的回调函数[^4]。 #### 示例代码片段 下面给出一段简单的例子展示如何初始化一个基本的 TCP server: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <uv.h> void on_new_connection(uv_stream_t* server, int status) { if (status < 0) { fprintf(stderr, "New connection error %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("Connection accepted.\n"); // Handle the new connection... } else { uv_close((uv_handle_t*)client, NULL); } } int main() { uv_loop_t *loop = uv_default_loop(); uv_tcp_t server; uv_tcp_init(loop, &server); struct sockaddr_in addr; uv_ip4_addr("0.0.0.0", 7000, &addr); uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); int r = uv_listen((uv_stream_t*)&server, 128, on_new_connection); if (r) { fprintf(stderr, "Listen error %s\n", uv_strerror(r)); return 1; } printf("Server running at http://localhost:7000/\n"); return uv_run(loop, UV_RUN_DEFAULT); } ``` 这段C语言程序展示了怎样设置监听端口并通过回调机制接收新的连接请求. #### 学习资源推荐 除了上述提到的方法之外,还有许多在线教程可以帮助深入理解 libuv 的内部运作原理及其最佳实践案例。这些资料不仅限于官方文档,还包括由社区成员撰写的博客文章和技术分享等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值