当前位置: 首页 > article >正文

远场P2P穿越

什么叫远场P2P穿越

  • 远场P2P穿越(NAT穿越)是一种网络技术,用于实现不同NAT(网络地址转换)网络中的设备之间的直接通信,主要解决的是不同局域网下的设备如何建立直接连接的问题

相关概念

  • NAT:将私有IP转换为公网IP的技术
  • 穿透:突破NAT限制建立连接的过程

常见的穿透技术

  • STUN(simple Traversaf of UDP through NAT)
struct stun_header {
    unit16_t type;
    unit16 length;
    unit32_t cookie;
    uint8_t transaction_id[12];
}
  • TURN( Traversal Using Relays around NAT)
// TURN中继服务器配置示例
const char* TURN_SERVER = "turn:stun.example.com:3478";
const char* USERNAME = "user";
const char* PASSWORD = "pass";
  • ICE (Interactive Connectivity Establishment)
enum class ICECandidateType {
    Host, // 本地地址
    ServerReflexive, // STUN反射地址
    PeerReflexive, // 对等反射地址
    Relay // TURN 中继地址
}

实现远场P2P穿透的基本步骤

class P2PConnection {
public:
    P2PConnection() {
        // 1.初始化STUN/TURN客户端
        initSTUN();
        initTURN();
        // 2.收集ICE候选者
        gatherCandidates();
    }
private:
    void initSTUN() {
        // 配置STUN服务器
        const char* STUN_SERVER = "stun:stun.l.google.com:19302";
    }




  • 穿透流程:
    • 设备A和B都连接到了STUN服务器
    • 获取各自的公网IP和端口
    • 通过信令服务器交换链接信息
    • 尝试直接连接
    • 如果直接连接失败,使用TURN中继

常见的应用场景

  • 视频通过
  • P2P文件传输
  • 远程控制
  • 游戏联机

示例代码

  • 使用libnice库
/**
 * @file testRemoteP2pCross.cpp
 * @brief P2P文件传输程序
 * @details 实现基于ICE和SSL的P2P安全文件传输功能
 */

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <thread>
#include <nice/agent.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <glib.h>

class P2PFileTransfer {
private:
    NiceAgent* agent;
    GMainLoop* loop;
    guint stream_id;
    SSL_CTX* ssl_ctx;
    SSL* ssl;
    std::string remote_credentials;
    bool is_sender;
    
    // 文件传输缓冲区大小
    static const int BUFFER_SIZE = 8192;

public:
    P2PFileTransfer(bool sender) : is_sender(sender) {
        // 初始化 GLib
        g_networking_init();
        loop = g_main_loop_new(NULL, FALSE);
        
        // 初始化 ICE agent
        agent = nice_agent_new(g_main_loop_get_context(loop),
                             NICE_COMPATIBILITY_RFC5245);
                             
        // 配置 STUN 服务器
        g_object_set(G_OBJECT(agent), 
                    "stun-server", "stun.l.google.com",
                    "stun-server-port", 19302,
                    NULL);
                    
        // 初始化 SSL
        initializeSSL();
    }
    
    ~P2PFileTransfer() {
        g_object_unref(agent);
        g_main_loop_unref(loop);
        SSL_free(ssl);
        SSL_CTX_free(ssl_ctx);
    }

private:
    void initializeSSL() {
        SSL_library_init();
        OpenSSL_add_all_algorithms();
        SSL_load_error_strings();
        
        ssl_ctx = SSL_CTX_new(TLS_method());
        if (!ssl_ctx) {
            throw std::runtime_error("SSL context creation failed");
        }
        
        // 配置 SSL 证书和私钥
        if (SSL_CTX_use_certificate_file(ssl_ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) {
            throw std::runtime_error("Certificate loading failed");
        }
        if (SSL_CTX_use_PrivateKey_file(ssl_ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
            throw std::runtime_error("Private key loading failed");
        }
    }

    static void candidateGatheringDone(NiceAgent* agent, guint stream_id, gpointer data) {
        P2PFileTransfer* p2p = static_cast<P2PFileTransfer*>(data);
        gchar* local_sdp = nice_agent_generate_local_sdp(agent);
        std::cout << "Local SDP:\n" << local_sdp << std::endl;
        g_free(local_sdp);
    }

    static void componentStateChanged(NiceAgent* agent, guint stream_id, 
                                    guint component_id, guint state,
                                    gpointer data) {
        if (state == NICE_COMPONENT_STATE_READY) {
            std::cout << "ICE connection established!" << std::endl;
            P2PFileTransfer* p2p = static_cast<P2PFileTransfer*>(data);
            p2p->startTransfer();
        }
    }

public:
    void setupConnection() {
        // 添加媒体流
        stream_id = nice_agent_add_stream(agent, 1);
        
        // 设置回调函数
        g_signal_connect(G_OBJECT(agent), "candidate-gathering-done",
                        G_CALLBACK(candidateGatheringDone), this);
        g_signal_connect(G_OBJECT(agent), "component-state-changed",
                        G_CALLBACK(componentStateChanged), this);
                        
        // 开始收集候选者
        nice_agent_gather_candidates(agent, stream_id);
        
        // 运行主循环
        std::thread loop_thread([this]() {
            g_main_loop_run(this->loop);
        });
        loop_thread.detach();
    }

    void sendFile(const std::string& filename) {
        if (!is_sender) {
            throw std::runtime_error("This instance is not configured as sender");
        }

        std::ifstream file(filename, std::ios::binary);
        if (!file) {
            throw std::runtime_error("Cannot open file: " + filename);
        }

        // 首先发送文件名和大小
        file.seekg(0, std::ios::end);
        size_t filesize = file.tellg();
        file.seekg(0, std::ios::beg);

        // 发送文件信息
        std::string file_info = filename + ":" + std::to_string(filesize);
        SSL_write(ssl, file_info.c_str(), file_info.length());

        // 发送文件内容
        std::vector<char> buffer(BUFFER_SIZE);
        while (!file.eof()) {
            file.read(buffer.data(), BUFFER_SIZE);
            std::streamsize bytes_read = file.gcount();
            if (bytes_read > 0) {
                SSL_write(ssl, buffer.data(), bytes_read);
            }
        }

        file.close();
    }

    void receiveFile() {
        if (is_sender) {
            throw std::runtime_error("This instance is not configured as receiver");
        }

        // 接收文件信息
        char info_buffer[1024];
        int bytes = SSL_read(ssl, info_buffer, sizeof(info_buffer));
        std::string file_info(info_buffer, bytes);

        // 解析文件名和大小
        size_t pos = file_info.find(':');
        std::string filename = file_info.substr(0, pos);
        size_t filesize = std::stoull(file_info.substr(pos + 1));

        // 接收文件内容
        std::ofstream file(filename, std::ios::binary);
        std::vector<char> buffer(BUFFER_SIZE);
        size_t total_received = 0;

        while (total_received < filesize) {
            int bytes = SSL_read(ssl, buffer.data(), BUFFER_SIZE);
            if (bytes > 0) {
                file.write(buffer.data(), bytes);
                total_received += bytes;
            }
        }

        file.close();
    }

private:
    void startTransfer() {
        // 创建 SSL 连接
        ssl = SSL_new(ssl_ctx);
        // 设置 SSL 为服务器或客户端模式
        if (is_sender) {
            SSL_set_connect_state(ssl);
        } else {
            SSL_set_accept_state(ssl);
        }

        // 开始文件传输
        if (is_sender) {
            sendFile("example.txt");
        } else {
            receiveFile();
        }
    }
};

// 使用示例
int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cout << "Usage: " << argv[0] << " [send|receive]" << std::endl;
        return 1;
    }

    try {
        bool is_sender = std::string(argv[1]) == "send";
        P2PFileTransfer p2p(is_sender);
        p2p.setupConnection();

        // 等待用户输入远程端的连接信息
        std::cout << "Enter remote SDP: " << std::endl;
        std::string remote_sdp;
        std::getline(std::cin, remote_sdp);

        // 这里应该处理远程 SDP 并建立连接
        // ...

        // 保持程序运行
        std::string input;
        std::getline(std::cin, input);

    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

http://www.kler.cn/a/464497.html

相关文章:

  • 【计算机网络】什么是AC和AP?
  • 【数据结构】链表(2):双向链表和双向循环链表
  • 数据结构知识收集尊享版(迅速了解回顾相关知识)
  • Coroutine 基础八 —— Flow 操作符(二)
  • C++并发:并发操作的同步
  • 代码随想录算法训练营第二十四天-回溯算法-90. 子集II
  • Facebook元宇宙项目中的智能合约应用:提升虚拟空间的自治能力
  • 《探秘计算机视觉与深度学习:开启智能视觉新时代》
  • HTML——30.视频引入
  • Spring Boot 中的 classpath详解
  • 专业高程转换工具 | 海拔高度与椭球高度在线转换系统
  • PHP框架+gatewayworker实现在线1对1聊天--发送消息(6)
  • Elasticsearch:当混合搜索真正发挥作用时
  • 选择器(结构伪类选择器,伪元素选择器),PxCook软件,盒子模型
  • [CTF/网络安全] 攻防世界 warmup 解题详析
  • 达达求变这一年,即时零售江湖潮起两岸阔
  • vue2+echarts实现水球+外层动效
  • 无人机飞手培训机构大量新增,考取飞手证参军入伍还有优势吗?
  • PHP框架+gatewayworker实现在线1对1聊天--gatewayworker说明(2)
  • 怎么免费查询企业的行政监管信息?
  • 入门嵌入式(二)——中断
  • 设计模式 结构型 适配器模式(Adapter Pattern)与 常见技术框架应用 解析
  • CPO-SVMD分解 | Matlab实现CPO-SVMD豪猪算法优化逐次变分模态分解
  • 图像概念与分类
  • Linux下Shell编程之ps命令详解及示例
  • std optional 的使用