首页 > 其他分享 >基于Boost.Asio实现端口映射器

基于Boost.Asio实现端口映射器

时间:2023-11-24 14:23:32浏览次数:55  
标签:Asio socket service Boost client io error boost 端口映射

Boost.Asio 是一个功能强大的 C++ 库,用于异步编程和网络编程,它提供了跨平台的异步 I/O 操作。在这篇文章中,我们将深入分析一个使用 Boost.Asio 实现的简单端口映射服务器,该服务器能够将本地端口的数据包转发到指定的远程服务器上。

端口映射通常用于将一个网络端口上的流量转发到另一个网络端口。这对于实现网络中间人攻击、内网穿透等场景非常有用。我们将使用 Boost.Asio 提供的异步操作来实现这个简单而功能强大的端口映射服务器。

#include <list>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/enable_shared_from_this.hpp>

using boost::asio::ip::tcp;

首先,让我们简要概述代码的主要类:

  • socket_client 类:继承了 boost::enable_shared_from_thistcp::socket,用于表示客户端的套接字。
  • socket_pipe 类:表示端口映射的管道,负责在两个客户端之间传递数据。
  • async_listener 类:用于异步监听指定端口的连接请求,通过回调函数处理连接。
  • port_map_server 类:管理多个监听器,支持添加端口映射规则,并处理连接请求。

1.1 socket_client

socket_client 类继承自 boost::enable_shared_from_thistcp::socket。通过 create 静态方法创建一个 socket_client 实例,提供了共享指针的方式管理对象的生命周期。

如下代码是一个使用 Boost.Asio 库创建的异步 TCP 客户端类。

class socket_client
    : public boost::enable_shared_from_this<socket_client>
    , public tcp::socket
{
public:
    typedef boost::shared_ptr<socket_client> pointer;

    static pointer create(boost::asio::io_service& io_service)
    {
        return pointer(new socket_client(io_service));
    }

public:
    socket_client(boost::asio::io_service& io_service)
        :tcp::socket(io_service)
    {
    }
};

以下是对该类的概括:

  • 类名socket_client
  • 继承关系
    • 继承自 boost::enable_shared_from_this<socket_client>,这允许在异步操作中安全地使用 shared_from_this,以避免悬挂指针的问题。
    • 继承自 tcp::socket,表示该类是一个 TCP 套接字。
  • 公共成员类型
    • pointerboost::shared_ptr<socket_client> 类型的别名,用于管理该类的实例。
  • 公共静态函数
    • create:工厂方法,用于创建 socket_client 的实例。通过此方法获取了一个智能指针指向新创建的实例。
  • 公共构造函数
    • socket_client(boost::asio::io_service& io_service):构造函数,接受一个 boost::asio::io_service 引用,用于初始化基类 tcp::socket

该类的目的是提供一个异步 TCP 客户端的基本结构,使其能够与 Boost.Asio 库中的异步 I/O 操作协同工作。实际使用时,可以根据具体需求扩展该类,添加成员函数和操作,以实现特定的异步操作逻辑。

1.2 socket_pipe

socket_pipe 类用于处理两个客户端之间的数据传递。通过异步操作实现了从一个客户端读取数据,并将数据写入另一个客户端。出现错误时,会关闭两个客户端的连接。这里使用了递归的方式,实现了数据的循环传递。

如下代码是一个使用是一个 socket_pipe 类的定义,用于在两个 socket_client 实例之间建立数据传输管道。

class socket_pipe
{
public:
    socket_pipe(socket_client::pointer read, socket_client::pointer write)
        :read_socket_(*read), write_socket_(*write)
    {
        read_ = read;
        write_ = write;
        begin_read();
    }

private:
    void begin_read()
    {
        read_socket_.async_read_some(boost::asio::buffer(data_, max_length),
            boost::bind(&socket_pipe::end_read, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    }

    void end_read(const boost::system::error_code& error, size_t bytes_transferred)
    {
        if (error)
            handle_error(error);
        else
            begin_write(bytes_transferred);
    }

    void begin_write(int bytes_transferred)
    {
        boost::asio::async_write(write_socket_,
            boost::asio::buffer(data_, bytes_transferred),
            boost::bind(&socket_pipe::end_write, this,
                boost::asio::placeholders::error));
    }

    void end_write(const boost::system::error_code& error)
    {
        if (error)
            handle_error(error);
        else
            begin_read();
    }

    void handle_error(const boost::system::error_code& error)
    {
        read_socket_.close();
        write_socket_.close();

        delete this;
    }

private:
    socket_client& read_socket_;
    socket_client& write_socket_;

    socket_client::pointer read_;
    socket_client::pointer write_;

    enum { max_length = 1024 };
    char data_[max_length];
};

以下是对该类的概括:

  • 类名socket_pipe
  • 公共构造函数
    • socket_pipe(socket_client::pointer read, socket_client::pointer write):构造函数,接受两个 socket_client::pointer 实例,一个用于读取数据 (read_socket_),另一个用于写入数据 (write_socket_)。在构造函数中,调用了 begin_read 函数,启动了异步读取操作。
  • 私有成员函数
    • begin_read():启动异步读取操作,使用 read_socket_.async_read_some 异步读取数据。
    • end_read(const boost::system::error_code& error, size_t bytes_transferred):读取操作完成时的回调函数,处理可能的错误,如果没有错误则调用 begin_write 启动异步写入操作。
    • begin_write(int bytes_transferred):启动异步写入操作,使用 boost::asio::async_write 异步写入数据。
    • end_write(const boost::system::error_code& error):写入操作完成时的回调函数,处理可能的错误,如果没有错误则调用 begin_read 启动下一轮异步读取操作。
    • handle_error(const boost::system::error_code& error):处理错误的函数,关闭读取和写入套接字,并释放当前 socket_pipe 实例。
  • 私有成员变量
    • socket_client& read_socket_:引用传递的读取套接字。
    • socket_client& write_socket_:引用传递的写入套接字。
    • socket_client::pointer read_:指向读取套接字的智能指针。
    • socket_client::pointer write_:指向写入套接字的智能指针。
    • enum { max_length = 1024 };:定义了最大数据长度。
    • char data_[max_length];:存储数据的缓冲区。

该类的主要目的是在两个 socket_client 之间实现数据的双向传输,通过异步操作实现了循环的读取和写入过程。在错误处理中,如果出现错误,会关闭套接字并释放当前的 socket_pipe 实例。

1.3 async_listener

async_listener 类负责异步监听指定端口,并通过回调函数处理连接。在连接建立时,会调用用户提供的回调函数进行处理。通过 begin_accept 方法开始异步监听。

如下代码是一个使用 async_listener 类的定义,用于异步监听指定端口的连接。

class async_listener
{
public:
    typedef boost::function<void(socket_client::pointer client)> accept_handler;
    typedef boost::shared_ptr<async_listener> pointer;

public:
    async_listener(short port, boost::asio::io_service& io_service)
        :io_service_(io_service),
        acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
    {
        begin_accept();
    }

    void begin_accept()
    {
        socket_client::pointer client = socket_client::create(io_service_);
        acceptor_.async_accept(*client,
            boost::bind(&async_listener::end_accept, this, client,
                boost::asio::placeholders::error));
    }

    void end_accept(socket_client::pointer client, const boost::system::error_code& error)
    {
        if (error)
            handle_error(error);

        begin_accept();

        if (!handle_accept.empty())
            handle_accept(client);
    }

    void handle_error(const boost::system::error_code& error)
    {
    }

public:
    accept_handler handle_accept;

private:
    tcp::acceptor acceptor_;
    boost::asio::io_service& io_service_;
};

以下是对该类的概括:

  • 类名async_listener
  • 公共成员类型
    • accept_handlerboost::function<void(socket_client::pointer client)> 类型的别名,用于定义连接建立时的回调函数。
    • pointerboost::shared_ptr<async_listener> 类型的别名,用于管理该类的实例。
  • 公共构造函数
    • async_listener(short port, boost::asio::io_service& io_service):构造函数,接受一个短整型端口号和一个 boost::asio::io_service 引用。在构造函数中,创建了一个 TCP 接受器 (acceptor_) 并调用 begin_accept 启动异步接受操作。
  • 公共函数
    • begin_accept():启动异步接受操作,创建一个新的 socket_client 实例,并调用 acceptor_.async_accept 异步等待连接的建立。
    • end_accept(socket_client::pointer client, const boost::system::error_code& error):异步接受操作完成时的回调函数,处理可能的错误,如果没有错误则调用 begin_accept 启动下一轮异步接受操作。如果定义了 handle_accept 回调函数,则调用它并传递新连接的 socket_client 实例。
  • 私有成员函数
    • handle_error(const boost::system::error_code& error):处理错误的函数,目前仅为空实现。
  • 公共成员变量
    • accept_handler handle_accept:用于存储用户定义的连接建立时的回调函数。
  • 私有成员变量
    • tcp::acceptor acceptor_:TCP 接受器,用于监听连接。
    • boost::asio::io_service& io_service_:引用传递的 io_service,用于执行异步操作。

该类的主要目的是实现异步监听,一旦有连接建立,就通过回调函数通知用户,并通过 handle_error 处理可能的错误。在连接建立后,会继续监听新的连接。

1.4 port_map_server

port_map_server 类管理多个监听器,支持动态添加端口映射规则。在连接建立时,会调用 handle_accept 处理连接请求。通过 begin_connect 方法开始异步连接远程服务器。

如下代码是一个 port_map_server 类的定义,它通过异步监听多个本地端口,并将连接映射到远程服务器的不同端口。

class port_map_server
{
public:
    port_map_server(boost::asio::io_service& io_service) :io_service_(io_service)
    {
    }

    void add_portmap(short port, tcp::endpoint& remote_endpoint)
    {
        async_listener::pointer listener(new async_listener(port, io_service_));
        listeners.push_back(listener);

        listener->handle_accept = boost::bind(&port_map_server::handle_accept
            , this, remote_endpoint, _1);
    }

    void handle_accept(tcp::endpoint remote_endpoint, socket_client::pointer client)
    {
        begin_connect(remote_endpoint, client);
    }

    void begin_connect(tcp::endpoint& remote_endpoint, socket_client::pointer socket_local)
    {
        socket_client::pointer socket_remote = socket_client::create(io_service_);
        socket_remote->async_connect(remote_endpoint,
            boost::bind(&port_map_server::end_connect, this,
                boost::asio::placeholders::error, socket_local, socket_remote));
    }

    void end_connect(const boost::system::error_code& error, socket_client::pointer socket_local, socket_client::pointer socket_remote)
    {
        if (error)
        {
            handle_error(error);
        }
        else
        {
            new socket_pipe(socket_local, socket_remote);
            new socket_pipe(socket_remote, socket_local);
        }
    }

    void handle_error(const boost::system::error_code& error)
    {
    }

private:
    boost::asio::io_service& io_service_;
    std::list<async_listener::pointer> listeners;
};

以下是对该类的概括:

  • 类名port_map_server
  • 公共构造函数
    • port_map_server(boost::asio::io_service& io_service):构造函数,接受一个 boost::asio::io_service 引用。
  • 公共函数
    • add_portmap(short port, tcp::endpoint& remote_endpoint):添加端口映射规则的函数。为指定端口创建一个新的 async_listener 实例,并将其添加到 listeners 列表中。同时,设置 handle_accept 回调函数,以便在新连接建立时调用 handle_accept 函数。
  • 私有成员函数
    • handle_accept(tcp::endpoint remote_endpoint, socket_client::pointer client):处理新连接建立时的回调函数。在此函数中,调用 begin_connect 启动异步连接到远程服务器的操作。
    • begin_connect(tcp::endpoint& remote_endpoint, socket_client::pointer socket_local):启动异步连接到远程服务器的操作,创建一个新的远程套接字。
    • end_connect(const boost::system::error_code& error, socket_client::pointer socket_local, socket_client::pointer socket_remote):处理异步连接操作完成时的回调函数。如果连接成功,创建两个 socket_pipe 实例,分别用于将数据从本地传输到远程和从远程传输回本地。
    • handle_error(const boost::system::error_code& error):处理错误的函数,目前仅为空实现。
  • 私有成员变量
    • boost::asio::io_service& io_service_:引用传递的 io_service,用于执行异步操作。
    • std::list<async_listener::pointer> listeners:存储多个 async_listener 实例的列表。

该类的主要目的是通过创建多个 async_listener 实例,监听多个本地端口,并在新连接建立时将其映射到远程服务器的不同端口。在连接建立后,会启动异步连接到远程服务器的操作,并创建数据传输的管道。

1.5 port_map_server

这是程序的 main 函数,负责创建一个 boost::asio::io_service 实例,设置两个远程服务器的端点,然后创建一个 port_map_server 实例并添加两个端口映射规则。最后,通过调用 io_service.run() 开始事件循环。

以下是对 main 函数的概括:

  • 函数功能
    • 创建一个 boost::asio::io_service 实例,用于管理异步操作的事件循环。
    • 定义两个远程服务器的端点 (ep1ep2),分别是 192.168.1.100:80192.168.1.200:80
    • 创建一个 port_map_server 实例,该实例使用上述 io_service
    • 通过 add_portmap 函数向 port_map_server 添加两个端口映射规则,将本地端口 5000 映射到远程服务器 192.168.1.100:80,将本地端口 6000 映射到远程服务器 192.168.1.200:80
    • 调用 io_service.run() 开始事件循环,等待异步操作的完成。
  • 异常处理
    • 使用了 trycatch 块,捕获任何可能抛出的异常,并在 catch 块中忽略异常。
  • 返回值
    • 返回整数 0 表示程序正常结束。

这个 main 函数的作用是启动异步事件循环,使得 port_map_server 开始监听指定端口,接受连接,并将连接映射到远程服务器上。

int main(int argc, char* argv[])
{
    try
    {
        boost::asio::io_service io_service;

        tcp::endpoint ep1(boost::asio::ip::address_v4::from_string("192.168.1.100"), 80);
        tcp::endpoint ep2(boost::asio::ip::address_v4::from_string("192.168.1.200"), 80);

        port_map_server server(io_service);

        // 访问本机5000端口,将数据包转发到 8.141.58.64:80
        server.add_portmap(5000, ep1);
        // 访问本机6000端口,将数据包转发到 8.141.58.64:80
        server.add_portmap(6000, ep2);

        io_service.run();
    }
    catch (...) {}
    return 0;
}

标签:Asio,socket,service,Boost,client,io,error,boost,端口映射
From: https://www.cnblogs.com/LyShark/p/17853631.html

相关文章

  • R语言集成模型:提升树boosting、随机森林、约束最小二乘法加权平均模型融合分析时间序
    原文链接:http://tecdat.cn/?p=24148原文出处:拓端数据部落公众号 最近我们被要求撰写关于集成模型的研究报告,包括一些图形和统计输出。特别是在经济学/计量经济学中,建模者不相信他们的模型能反映现实。比如:收益率曲线并不遵循三因素的Nelson-Siegel模型,股票与其相关因素之间的......
  • MacOS 端口映射
    macbook下,要绑定80端口的话。一种方式是用root权限启动,即sudo启动服务进程。但sudo指令存在一定的安全问题,能不使用的情况下我们都尽量不要使用。所以这里给出另外一种解决方法端口映射在 /etc/pf.anchors/ 目录下创建一份 xxx.forwarding (xxx可以自定义)$s......
  • centos7.9 部署FastDFS+Nginx本地搭建文件服务器 高性能的文件服务器集群 同时实现在
    前言FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线......
  • (DC/DC)Buck、Boost电路原理、电源调制方式、芯片内部、设计参数!
    DC/DC转换器是直流/直流转换器,是一种将直流电压从高电压转换为低电压或从低电压转换为高电压的电源转换设备。Buck和Boost是两种基本的DC/DC转换器拓扑。Buck电路(降压型DC/DC转换器):原理:Buck电路通过控制开关(通常是晶体管)将输入电压降低。当晶体管开启时,电流增加,电压降低。当晶体......
  • AdaBoost算法解密:从基础到应用的全面解析
    本文全面而深入地探讨了AdaBoost算法,从其基础概念和原理到Python实战应用。文章不仅详细解析了AdaBoost的优缺点,还通过实例展示了如何在Python中实现该算法。关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人......
  • linux系统多版本boost共存
    因为几个库都用到boost,但是各个库依赖的boost最低版本不一样安装boost1.71tar-zxvfboost_1_71_0.tar.gz&&cdboost_1_71_0su-root./bootstrap.sh--with-libraries=all./b2./b2install 用./b2install把boost1.71安装在默认路径了,即/usr/local下,头文件和库文件分别位......
  • linux系统多版本boost库共存
    因为几个库都用到boost,但是各个库依赖的boost最低版本不一样安装boost1.71tar-zxvfboost_1_71_0.tar.gz&&cdboost_1_71_0su-root./bootstrap.sh--with-libraries=all./b2./b2install用./b2install把boost1.71安装在默认路径了,即/usr/local下,头文件和库文件分别......
  • ../include/types.hh:16:43: fatal error: boost/archive/text_oarchive.hpp: No such
     001、make编译报错如下:../include/types.hh:16:43:fatalerror:boost/archive/text_oarchive.hpp:Nosuchfileordirectory 002、 ......
  • 10 Tips to Boost Your Productivity with C# and Visual Studio 2008
    http://blogs.msdn.com/johnwpowell/archive/2008/03/23/10-tips-to-boost-your-productivity-with-c-and-visual-studio-2008.aspxhttp://www.microsoft.com/downloads/details.aspx?familyid=E5F902A8-5BB5-4CC6-907E-472809749973&displaylang=enhttp://dotnet.chinait......
  • 19.5 Boost Asio 传输结构体
    同步模式下的结构体传输与原生套接字实现方式完全一致,读者需要注意的是在接收参数是应该使用socket.read_some函数读取,发送参数则使用socket.write_some函数实现,对于套接字的解析同样使用强制指针转换的方法。服务端代码如下所示#include<iostream>#include<boost/asio.hpp>......