美文网首页WebRTC
medooze源码分析--启动服务器

medooze源码分析--启动服务器

作者: 音视频直播技术专家 | 来源:发表于2018-11-15 14:40 被阅读212次

    createEndpoint

    当我们打开index.js 后,看到的第一个重要的 API就是createEndpoint函数了。我们就以这个 API为开头,一步一步的分析一下medooze的运行机制。

    createEndpoint函数定义在 medooze-media-server 库中的 lib 目录下的 MediaServer.js 中。代码如下:

    /**
     * Create a new endpoint object
     * @memberof MediaServer
     * @param {String} ip   - External IP address of server, to be used when announcing the local ICE candidate
     * @returns {Endpoint} The new created endpoing
     */
    MediaServer.createEndpoint = function(ip)
    {
            //Cretate new rtp endpoint
            return new Endpoint(ip);
    };
    

    它的作用是公布 ICE 本地候选者,当做一个终端。

    顺着这个函数我们继续往下看,在该函数中会创建一个 Endpoint 对象。

    Endpoint

    medooze-media-server 库中的 lib 目录下的 Endpoint.js 文件是 Endpoint 的类文件。该类的作用如下:

    /**
     * An endpoint represent an UDP server socket.
     * The endpoint will process STUN requests in order to be able to associate the remote ip:port with the registered transport and forward any further data comming from that transport.
     * Being a server it is ICE-lite.
     */
    /**
     *endpoint 表示UDP服务器套接字。
     *endpoint 将处理STUN请求,以便能够将远程ip:port与注册的传输相关联,并转发来自该传输的任何进一步的通信数据。
     *作为一个服务器,它是轻量级的ICE。
    */
    

    在创建 Endpoint 对象时,会调用它的构造函数。其代码如下:

    constructor(ip)
     {
         //Store ip address of the endpoint
         this.ip = ip;
         //Create native endpoint
         this.bundle = new Native.RTPBundleTransport();
         //Start it
         this.bundle.Init();
         //Store all transports
         this.transports = new Set();
         //Create candidate
         this.candidate = new CandidateInfo("1", 1, "UDP", 33554431, ip, this.bundle.GetLocalPort(), "host");
         //Get fingerprint (global at media server level currently)
         this.fingerprint = Native.MediaServer.GetFingerprint().toString();
    }
    

    通过上面的代码可以看到 Endpoint 包括以下几个成员:

    • ip : STUN 服务器IP地址。
    • bundle:native层的Endpoint。
    • transports: 这是一个集合,用于存放所有用到的传输协议
    • candidate: ICE 候选者
    • fingerprint: 指纹,用于网络安全。

    接下来,我们分别看一下 Native.RTPBundleTransport 和 CandidateInfo。

    RTPBundleTransport

    RTPBundleTransport 类定义在 media-server 中的 include/RTPBundleTransport.h文件中。该类的构造函数如下:

    RTPBundleTransport::RTPBundleTransport()
    {
            //Init values
            socket = FD_INVALID;
            port = 0;
            
            //No thread
            setZeroThread(&thread);
            running = false;
            //Mutex
            pthread_mutex_init(&mutex,0);
            pthread_cond_init(&cond,0);
    }
    

    Endpoint 类的构函数中,首先创建了 RTPBundleTransport对象,然后又调用了该对象的 Init方法,其代码如下:

    int RTPBundleTransport::Init()
    {
            int retries = 0;
    
            sockaddr_in recAddr;
    
            //Clear addr
            memset(&recAddr,0,sizeof(struct sockaddr_in));
            //Init ramdon
            srand (time(NULL));
    
            //Set family
            recAddr.sin_family      = AF_INET;
    
            //Get two consecutive ramdom ports
            while (retries++<100)
            {
                    ...
    
                    //Create new sockets
                    socket = ::socket(PF_INET,SOCK_DGRAM,0);
                    //Get random
                    port = (RTPTransport::GetMinPort()+(RTPTransport::GetMaxPort()-RTPTransport::GetMinPort())*double(rand()/double(RAND_MAX)));
                    //Make even
                    port &= 0xFFFFFFFE;
                    //Try to bind to port
                    recAddr.sin_port = htons(port);
                    //Bind the rtp socket
                    if(bind(socket,(struct sockaddr *)&recAddr,sizeof(struct sockaddr_in))!=0)
                            //Try again
                            continue;
    
                    ...
                    Start();
                    //Done
                    Log("<RTPBundleTransport::Init()\n");
                    //Opened
                    return port;
            }
    
            //Error
            Error("-RTPBundleTransport::Init() | too many failed attemps opening sockets\n");
    
            //Failed
            return 0;
    }
    
    

    通过上面的代码我们可以看到, 在Init函数中,主要做了两件事儿:

    • 绑定端口号,打开sokcet服务。
    • 通过 Start() 启动了一个新的线程。对于线程的启动与所做的事情我们将在下篇文章中再做介绍。

    CandidateInfo

    在另外一个称为 semantic-sdp-js的项目中的lib中可以找到 CandidateInfo 类的定义。其构造函数如下:

    /**
    * CanditateInfo constructor
    * @constructor
    * @alias CandidateInfo
    * @param {String} foundation
    * @param {Number} componentId
    * @param {String} transport
    * @param {Number} priority
    * @param {String} address
    * @param {Number} port
    * @param {String} type
    * @param {String} relAddr
    * @param {String} relPort
    */
    constructor(foundation, componentId, transport, priority, address, port, type, relAddr, relPort) {
        this.foundation         = foundation;
        this.componentId        = componentId;
        this.transport          = transport;
        this.priority           = priority;
        this.address            = address;
        this.port               = port;
        this.type               = type;
        this.relAddr            = relAddr;
        this.relPort            = relPort;
    }
    

    其代码非常简单,就是将传入的一些参数保存起来。

    小结

    相关文章

      网友评论

        本文标题:medooze源码分析--启动服务器

        本文链接:https://www.haomeiwen.com/subject/tjzefqtx.html