• qt实现coturn穿透客户端,coturn服务器搭建


    coturn简介

    Coturn集成了stun+turn协议,实现NAT检测,穿透就需要通过stun协议, NAT检测无法进行穿越时就需要通过turn服务进行流媒体的转发了,而coturn就是将两者协议进行整合并进行择优优化。

    STUN 协议(Simple Traversal of UDP Through NATs) 即用 UDP简单的穿透 NAT 作为一个完整的 NAT 穿透解决 方案。

    网络穿透,即 NAT 穿透, 能够让公网机器找到私网机器,并提高下载速度。穿透的本质是给一个 NAT 路由器的公网 IP 地址与端口发送报文数据,对应私网机器能够收到报文数据。

    TURN,英文全称是Traversal Using Relays around NAT:Relay Extensions to Session Traversal Utilities for NAT,即使用中继穿透NAT:STUN的中继扩展。
    在这里插入图片描述

    coturn服务器搭建

    coturn服务通常搭建在公网环境,拥有可访问的公网IP,穿透成功可以获取客户端的公网IP和端口。
    局域网也可以搭建coturn服务,但只能获取局域网的IP和端口,意义不大。
    本章使用阿里云实验室搭建coturn,每次可用2个小时,做个demo实验足够了:阿里云实验室

    git clone https://github.com/coturn/coturn.git#克隆源码
    cd coturn
    #安装依赖
    sudo apt install pkg-config#ERROR: pkg-config
    sudo apt install libssl-dev#ERROR: OpenSSL Crypto development libraries are not installed properly in required location
    sudo apt install libevent-dev#ERROR: Libevent2 development libraries are not installed properly in required location
    #编译
    ./configure
    make 
    sudo make install
    
    #配置环境
    turnadmin -a -u 用户名 -p 密码 -r 域名(给自己的域名)
    turnadmin -a -u test -p 123456 -r chuwei
    /usr/local/bin#turnserver安装目录
    cd /usr/local/etc#配置文件所在目录
    sudo cp turnserver.conf.default turnserver.conf
    sudo vim turnserver.conf
    #添加如下内容
    listening-port=3478 
    external-ip=139.196.187.17 
    user=test:123456
    realm=chuwei
    
    turnserver -o -a -f -v -r chuwei#启动turnserver
    netstat -ntpl#查看活跃端口,能看到启动的turnserver
    lsof -i:3478#验证是否在监听
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    coturn服务验证

    访问https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/
    输入coturn服务器IP和端口,用户名和密码,点击Add Server,再点击Gather candidatesm,可以看到已经获取了udp公网IP和端口。
    使用的火狐浏览器,谷歌浏览器报701错误。
    在这里插入图片描述
    大致包含的内容:
    本机 IP 地址
    本机用于WebRTC通信的端口号
    候选者类型,包括 host、srflx 和 relay
    优先级
    传输协议

    candidate事件type字段取值分别为host、srflx、relay:
    host(Host candidate):从本地网卡上获取的地址
    srflx(Server reflexive candidate):STUN 返回的该客户端的地址
    relay(Relay reflexive candidate)::TURN 服务器为该客户端分配的中继地址
    本地的candidate与远端candidate构成的每一对都有一定的优先级,按优先级排序进行连通性检查。最后从有效的candidate组合中选择优先级最高的作为传输地址,用于建立P2P连接。

    qt实现coturn穿透

    qt实现coturn客户端,穿透成功返回公网IP和端口

    #include "ccmainwindow.h"
    #include "ui_ccmainwindow.h"
    
    ccMainWindow::ccMainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::ccMainWindow)
    {
        ui->setupUi(this);
    
        pUdp = new QUdpSocket(this);
    
        session = (chwRtcSession*)calloc(sizeof(chwRtcSession),1);
        session->context.avinfo = (chwAVInfo*)calloc(sizeof(chwAVInfo),1);
        session->context.streamConfig = (chwStreamConfig*)calloc(sizeof(chwStreamConfig),1);
        strcpy(session->context.avinfo->rtc.iceServerIP,"101.133.145.11");
        session->context.avinfo->rtc.iceStunPort=3478;
        strcpy(session->ice.server.serverIp , "101.133.145.11");//穿透服务器IP
        session->ice.server.serverPort = 3478;//穿透服务器端口
        session->context.avinfo->rtc.hasIceServer=1;
        session->context.streamConfig->localPort = 9099;
    
        int err = 0;
        if(session->context.avinfo->rtc.hasIceServer&&session->ice.server.stunPort==0)
        {
            err=chw_ice_request(&session->ice.server,session->context.streamConfig->localPort);
            if(err != 0)
                printf("stun request fail!");
        }
    }
    
    ccMainWindow::~ccMainWindow()
    {
        delete ui;
    }
    
    
    void ccMainWindow::on_pushButton_initudp_clicked()
    {
        pUdp->bind(QHostAddress::Any,ui->lineEdit_localport->text().toUInt());
        connect(pUdp, SIGNAL(readyRead()),this, SLOT(readPendingDatagrams()));
    }
    
    void ccMainWindow::on_pushButton_initudp_send_clicked()
    {
        pUdp->writeDatagram(ui->lineEdit_sendMsg->text().toLatin1().data(),ui->lineEdit_sendMsg->text().size(),
                            QHostAddress(ui->lineEdit_remoteIP->text()),ui->lineEdit_remotePort->text().toUInt());
        pUdp->waitForBytesWritten();
    }
    
    void ccMainWindow::readPendingDatagrams()
    {
        QByteArray datagram;
        while (pUdp->hasPendingDatagrams()) {
    
            datagram.resize(pUdp->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;
    
            pUdp->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
            ui->textBrowser->append(datagram.data());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    打印输出

    remoteIp=101.133.145.11,port=3478
    udp server is starting,localPort=9099
    stun ip=180.111.104.1,stunport=7343
    
    • 1
    • 2
    • 3
  • 相关阅读:
    Kotlin协程 - launch原理 笔记
    MyBatis:核心配置文件
    jQuery Validation Engine验证模拟的下拉列表非select
    天软特色因子看板 (2023.09 第05期)
    用postman发请求显示类型转换错误
    Google Earth Engine(GEE)—— GRIDMET: 爱达荷大学网格化地表气象数据集
    剑指 Offer 27. 二叉树的镜像
    Paxos算法
    什么是WMS系统条码化管理
    从硬件“卷”到UI交互,车企怎样才能掌握智能化「灵魂」
  • 原文地址:https://blog.csdn.net/weixin_40355471/article/details/126086797