libuv实现tcp代理服务器

本文档介绍了如何使用libuv库实现一个TCP代理服务器,包括启动TCP服务、处理连接、数据转发及异常处理。详细讲解了uv_err_name、uv_ip4_addr、uv_tcp_init、uv_tcp_bind、uv_listen和uv_accept等关键API的使用,并提供了源码示例。

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

概述

为了学习libuv的tcp相关函数使用,实现了一个tcp代理服务。

1 启动TCP服务
2 如果有新的连接X,则向代理地址建立连接Y,并关联X和Y成组
3 如果X收到数据包,发往Y;反之如果Y收到数据包发往X
4 如果X或者Y连接异常,关闭此组连接
5 代理服务退出时,清理所有组,清理TCP服务

API简介

uv_err_name

出现错误可以通过uv_strerror和uv_err_name找错误原因。

int r = uv_accept(server, stream);
fprintf(stderr, "uv_accept error %s\n", uv_err_name(r));

uv_ip4_addr

struct sockaddr_in m_local;
struct sockaddr_in m_remote;
...
uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &m_local);

将给定的ip地址和端口转换成sockaddr_in结构体,原生编程的时候,设置ip和端口需要至少五行,用这个方法可以简化操作

uv_tcp_init

初始化 tcp 对象

uv_loop_t* m_loop;
...
m_loop = uv_default_loop();
...
uv_tcp_t m_tcpServer;
...
uv_tcp_init(m_loop, &m_tcpServer);//初始化tcp server对象

uv_tcp_bind

等同于原生API的 bind() 方法

uv_tcp_bind(&m_tcpServer, (const struct sockaddr*) &m_local, 0);

uv_tcp_bind() 的第三个参数 flag 一般是0,如果想使用IP6,可以使用 UV_TCP_IPV6ONLY

enum uv_tcp_flags {
   
  /* Used with uv_tcp_bind, when an IPv6 address is used. */
  UV_TCP_IPV6ONLY = 1
};

uv_listen

与listen作用类似,增加了回调函数,有新连接来时会触发回调。

uv_listen((uv_stream_t*)&m_tcpServer, 50, OnAccept);

uv_accept

在OnAccept回调中执行uv_accept,用socket与stream关联,stream需要先分配内存和初始化。

int r;
uv_stream_t* stream;
...
uv_tcp_init(pProxy->m_loop, (uv_tcp_t*) stream);
...
r = uv_accept(server, stream);
uv_err_name(r)

源码演示

//
/*
在入口函数中包含 _CrtDumpMemoryLeaks();  
即可检测到内存泄露
*/
#define CRTDBG_MAP_ALLOC  
#include <stdlib.h>  
#include <crtdbg.h>  
//

#include <conio.h>    //for kbhit()
#include "stdafx.h"
#include "uv.h"
#include <map>
#include <algorithm>
using namespace std;

#define container_of(ptr, type, member) \
    ((type *) ((char *) (ptr) - offsetof(type, member)))

typedef void* (*proc_func)(char* buff, size_t size);

class CProxy
{
   
public:
    CProxy(const char* sip, int sport, const char* dip, int dport, uv_loop_t* loop = NULL)
    {
   
        uv_ip4_addr(sip, sport, &m_local);
        uv_ip4_addr(dip, dport, &m_remote);
        if (NULL == loop)
        {
   
            m_loop = uv_default_loop();
        }
        else
        {
   
            m_loop = loop;
        }
    }

    int Start()
    {
   
        int r = 0;
        
        r = uv_tcp_init(m_loop, &m_tcpServer);
        if (r)
        {
   
            return r;
        }

        r = uv_tcp_bind(&m_tcpServer, (const struct sockaddr*) &m_local, 0);
        if (r)
        {
   
            uv_err_name(r);
            return r;
        }

        r = uv_listen((uv_stream_t*)&m_tcpServer, 50, OnAccept);
 
### 关于 libuv教程、入门指南以及示例代码 #### 推荐学习资源 总结而言,《libuv 学习代码实战指南》是探索 libuv 世界的宝贵资源[^1]。此书不仅提供了丰富的理论知识,还包含了大量实用的案例研究,帮助读者掌握解决实际问题的方法。 #### 构建与配置指导 当构建 LibUV 时,可以使用 CMake 命令行或 IDE(如 Visual Studio 或 CLion)加载 `CMakeLists.txt` 文件并指定构建选项(例如安装路径、编译器标志等)。对于 Linux 用户来说,可以通过如下命令来生成 Makefile 并完成编译过程: ```bash mkdir build && cd build cmake .. make ``` 上述方法同样适用于其他支持的操作系统平台,在不同平台上仅需调整相应的工具链即可[^4]。 #### 实践中的注意事项 值得注意的是,在开源代码学习环境中,配置通常是通过命令行参数、环境变量或者编译时选项来进行管理的。因此,在尝试运行任何例子之前,请确保已经正确设置了开发环境,并了解如何利用这些机制自定义行为[^2]。 #### 示例代码片段 为了更好地理解 libuv 库的功能特性,这里给出一段简单的服务器端程序作为演示目的: ```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(server->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); free(client); } } 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); } ``` 这段代码展示了如何创建一个监听 TCP 连接的服务端应用程序。它初始化了一个事件循环实例,并绑定了本地地址和端口以等待客户端连接请求的到来。每当有新的连接到来时,便会触发回调函数 `on_new_connection()` 来处理该事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值