Webrtc 信令服务器实现

webrtc建联流程图

由上图可知,所谓的信令服务器其实就是将peer的offer/candidate/answer传给对端而已。这样的话实现方式就有很多种了,目前普遍的方式HTTP/HTTPS,WS/WSS。像webrtc-demo-peerconnection就是实现HTTP这种方式。本文使用WS(websocket)来实现。

简单的协议

peer签到

发送

srctype
就是peer的名称signin

返回

typecodemsg
signin_ack返回码消息

peer数据传输

发送

srcdsttype其他内容
发送端名称接收端名称trans...

返回

typecodemsg
trans_ack返回码消息

实现代码

1、下载websocketpp/jsoncpp代码:github上找

2、下载boost库

3、先使用cmake生成VS工程,然后编译jsoncpp

4、创建工程SignalServer

主代码如下:

#include "pch.h"

#include

#include

#include

#include

typedef websocketpp::server server;

server signalserver;

std::mutex g_wcmutex;

std::map g_mapWcInfo;

void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) 

{

    std::string strMsg = msg->get_payload();

    //解析json

    Json::Reader reader;

    Json::Value jMsg;

    if (!reader.parse(strMsg, jMsg))

    {

        return;

    }

    //获取当前的用户名称

    std::string strSrcName;

    Json::Value jName;

    if (!jMsg.isMember("src"))

    {

        return;

    }

    jName = jMsg["src"];

    strSrcName = jName.asString();

    //获取当前的操作

    std::string strOptType;

    Json::Value jOptType;

    if (!jMsg.isMember("type"))

    {

        return;

    }

    jOptType = jMsg["type"];

    strOptType = jOptType.asString();

    //数据转发

    if (strOptType.compare("signin") == 0)//peer签到

    {

        try {

            g_wcmutex.lock();

            g_mapWcInfo[strSrcName] = hdl;

            g_wcmutex.unlock();

            signalserver.send(hdl, "{\"type_ack\":\"signin\",\"code\":200,\"msg\":\"success\"}", websocketpp::frame::opcode::text);

        }

        catch (websocketpp::exception const & e) {

            std::cout << "Echo failed because: "

                << "(" << e.what() << ")" << std::endl;

        }

    }

    else if (strOptType.compare("trans") == 0)//数据转发

    {

        std::string strDstName;

        Json::Value jDstName;

        if (!jMsg.isMember("dst"))

        {

            return;

        }

        jDstName = jMsg["dst"];

        strDstName = jDstName.asString();

        g_wcmutex.lock();

        if (g_mapWcInfo.find(strDstName) == g_mapWcInfo.end())

        {

            g_wcmutex.unlock();

            signalserver.send(hdl, "{\"trans_ack\":\"trans\",\"code\":201,\"msg\":\"failed\"}", websocketpp::frame::opcode::text);

            return;

        }

        else

        {

            signalserver.send(g_mapWcInfo[strDstName], strMsg, websocketpp::frame::opcode::text);

            signalserver.send(hdl, "{\"trans_ack\":\"trans\",\"code\":200,\"msg\":\"success\"}", websocketpp::frame::opcode::text);

        }

        g_wcmutex.unlock();

    }

}

void on_close(websocketpp::connection_hdl hdl)

{

    server::connection_ptr  ptr = signalserver.get_con_from_hdl(hdl);

    g_wcmutex.lock();

    std::map::iterator it = g_mapWcInfo.begin();

    while (it != g_mapWcInfo.end())

    {

        server::connection_ptr  ptr1 = signalserver.get_con_from_hdl(it->second);

        if (ptr1 == ptr)

        {

            g_mapWcInfo.erase(it);

            break;

        }

    }

    g_wcmutex.unlock();

}

int main() 

{

    signalserver.set_close_handler(&on_close);

    signalserver.set_message_handler(&on_message);

    signalserver.set_access_channels(websocketpp::log::alevel::all);

    signalserver.set_error_channels(websocketpp::log::elevel::all);

    signalserver.init_asio();

    signalserver.listen(9002);

    signalserver.start_accept();

    signalserver.run();

}

使用网页在线websocket测试:websocket在线测试

上面是一个最简的信令服务器。