头图

以神卓互联为例,内网穿透是一种将局域网里的应用端口发布到公网访问的一种技术,这里的局域网是指NAT之后的网络。比如家里有一台笔记本,连接路由器的WIFI,笔记本上有一个Tomcat或者web应用,端口是8080,这个时候只可以通过家庭的局域网打开访问,同学在家里就不能访问你的笔记本上的web应用,而在笔记本上安装一个神卓互联的内网穿透客户端,添加一个需要映射的端口就可以实现同学在外面访问你的笔记本上的web应用,是不是很神奇。

应用场景
提供内网穿透服务
连接内网服务器,在外网演示内网web站点
无需服务器部署,快速调试本地程序,微信公众号开发利器
支持http、https协议站点,省去证书中间件复杂配置,http协议站点直接升级为https站点
支持TCP,UDP协议端口转发。支持数据库、SSH、远程桌面、网络摄像头等等开放到外网 包括但不限于以上场景。
内网穿透协议
标准的内网穿透协议是WanGooeTunnel通信协议

实现的功能
让外网请求通过各种复杂的路由和防火墙访问到内网的设备

成熟的内网穿透产品
目前国内正规的内网穿透产品是神卓互联和花生壳,商业化和成熟度都比较高客户群体有比较大。

实现内网穿透的方法
内网穿透基本上是以C语言实现,因为对性能的要求比较高

如何实现数据包的转发,由于内网穿透支持的协议比较多,这里就写一个简单的数据转发的代码,具体要实现成熟的功能还有很长的路要走

tcp_server* tcp_server::server_ptr = NULL;
tcp_server::tcp_server()
{}
 
tcp_server::tcp_server(const tcp_server&)
{}
 
bool tcp_server::server_listen()
{
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        perror("socket");
        return false;
    }
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8851);
    int ret = bind(listen_fd,(struct sockaddr*)&addr,sizeof(addr));
    if (ret < 0) {
        perror("bind");
        return false;
    }
    ret = listen(listen_fd,128);
    if (ret < 0) {
        perror("listen");
        return false;
    }
    //创建epoll树
    epoll_tree = epoll_create(1);
    //上epoll树
    struct epoll_event evt;
    evt.data.fd = listen_fd;
    evt.events = EPOLLIN;
    ret = epoll_ctl(epoll_tree, EPOLL_CTL_ADD, listen_fd, &evt);
    if (ret == -1)
    {
        perror("epoll_ctl");
        std::cout << "listen fd:" << listen_fd << std::endl;
        std::cout << "epoll_tree fd:" << epoll_tree << std::endl;
        return false;
    }
    std::cout << "established listen and create epoll tree" << std::endl;
    return true;
}
 
void tcp_server::server_run()
{
    if (!server_listen())
    {
        std::cout << "server listen error" << std::endl;
        server_close();
        return;
    }
    int size = sizeof(epr) / sizeof(epoll_event);
    //将所有主动连接的socket都记录并监听
    std::cout << "main server loop start" << std::endl;
    while(1) {
        epoll_count = epoll_wait(epoll_tree, epr, size, -1);
        for (int i = 0; i < epoll_count; i++) {
            if (epr[i].data.fd == listen_fd) { //判断是不是监听文件,如果监听文件有变化则将对应的通信文件添加到epoll树和vector
                int cfd = accept(listen_fd, NULL, NULL);
                if (cfd < 0){
                    perror("accept");
                    continue;
                }
                epoll_event evt;
                evt.data.fd = cfd;
                evt.events = EPOLLIN;
                int ret = epoll_ctl(epoll_tree, EPOLL_CTL_ADD, cfd, &evt);
                if (ret == -1)
                {
                    perror("epoll_ctl");
                    return ;
                }
                accept_list.push_back(cfd);
                std::cout << "Add a link file" << std::endl;
            }
            else{
                //获取消息并加入消息队列或转发
                char buf[100] = { 0 };
                int count = recv(epr[i].data.fd, buf, sizeof(buf), 0);
                if (count <= 0 ){
                    perror("recv");
                    continue;
                }
                for (auto it : accept_list){
                    //转发数据
                    if (it != epr[i].data.fd){
                        send(it, buf, count, 0);
                        std::cout << "send data: " << buf << " file describes: " << it << std::endl;
                    }
                }
            }
        }
    }
}
 
void tcp_server::server_close()
{
    for (auto it : accept_list){
        close(it);
    }
    close(listen_fd);
    close(epoll_tree);
}
 
tcp_server* tcp_server::getinstance()
{
    if (server_ptr != nullptr){
        return server_ptr;
    }
    server_ptr = new tcp_server;
    return server_ptr;
}

以上是通过epoll来实现高性能的端口数据转发,只支持linux系统,不支持windows,因为windows里没有epoll。

以下是神卓互联内网穿透windows版客户端绑定通道后的截图:

Linux版以ubuntu为例,安装之前需要先安装C++环境,

apt-get install g++

如图所示:

到此运行环境安装完成

接下来直接安装就可以了


代码小熊
2 声望0 粉丝