您当前的位置:首页 > 计算机 > 编程开发 > Other

webrtc之peerconnection_server详解

时间:08-18来源:作者:点击数:

前面分析webrtc的peerconnection_client协议流程,本文将分析webrtc的peerconnection_server流程。因为整个webrtc 的server分为turn-server,stun-server ,signal-server,这里的peerconnection_server中的server仅仅指的是signal-server。

Webrtc 部署框架

一、信令服务器基本原理

信令服务器的主要是负责呼叫,成员管理等一些控制和管理功能,类似电话的拨号流程。官方的demo的信令服务器比较简单,采用http协议承载交互信令,webrtc对信令协议本身没有定义,用户可以自由选型,你可以用http,websocket,sip,rtsp,甚至用tcp传自定义都无所谓,只要达到两个视频通话的peer能交互信息即可。Webrtc的官方demo,为了演示整个流程,采用传统的http协议,但实际商用,考虑安全,高可靠,性能等因素可能不会简单采用http协议,但协议交互的流程直接我们借鉴。

二、代码详解

peerconnection_server 本质就是一个简单的tcp服务器,这个服务器负责2个peer信息交换。

1)从main函数出发,解析命令行,创建socket,listen 监控端口。

absl::ParseCommandLine(argc, argv);
ListeningSocket listener;
  if (!listener.Create()) { //创建监听socket
    printf("Failed to create server socket\n");
    return -1;
  } else if (!listener.Listen(port)) {//监听socket
    printf("Failed to listen on server socket\n");
    return -1;
  }
PeerChannel clients;

2)进入大循环,采用select 网络模型,监听listen端口和accept进程的连接端口

while (!quit) {
    fd_set socket_set;
    FD_ZERO(&socket_set);
//将监听socket加入监听集
    if (listener.valid())
      FD_SET(listener.socket(), &socket_set);
//将接收socket加入监听集
    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
      FD_SET((*i)->socket(), &socket_set);
    struct timeval timeout = {10, 0};
//select事件模型监听
    if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
      printf("select failed\n");
      break;
    }
//遍历socket监听socket集,对已有事件的是socket数据进行接收和处理
    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
      DataSocket* s = *i;
      bool socket_done = true;
      if (FD_ISSET(s->socket(), &socket_set)) { //找到有事件的socket
     //读取socket数据,并进行解析
        if (s->OnDataAvailable(&socket_done) && s->request_received()) {
          ChannelMember* member = clients.Lookup(s);
          //如何请求socket对应成员存在或者第一次请求连接
          if (member || PeerChannel::IsPeerConnection(s)) {
            if (!member) {
              if (s->PathEquals("/sign_in")) {
                clients.AddMember(s);//如何请求成员ID不存在,则将该成员ID加入房间
              } else {
                printf("No member found for: %s\n", s->request_path().c_str());
                s->Send("500 Error", true, "text/plain", "",
                        "Peer most likely gone.");
                //成员找不到,回复500错误
              }
            } else if (member->is_wait_request(s)) {
              // no need to do anything.
              socket_done = false;
            } else {
              //成员找到,进行正常数据转发到
              ChannelMember* target = clients.IsTargetedRequest(s);
              if (target) {
                member->ForwardRequestToPeer(s, target);
              } else if (s->PathEquals("/sign_out")) {
    //退出连接,发peer登录响应
                s->Send("200 OK", true, "text/plain", "", "");
              } else {

                printf("Couldn't find target for request: %s\n",
                       s->request_path().c_str());
                s->Send("500 Error", true, "text/plain", "",
                        "Peer most likely gone.");
              }
            }
          } else {
              //不支持浏览器访问
            HandleBrowserRequest(s, &quit);
            if (quit) {
              printf("Quitting...\n");
              FD_CLR(listener.socket(), &socket_set);
              listener.Close();
              clients.CloseAll();
            }
          }
        }
      } else {
        socket_done = false;
      }
      //客户端端口连接,进行资源回收
      if (socket_done) {
        printf("Disconnecting socket\n");
        clients.OnClosing(s);
        assert(s->valid());  // Close must not have been called yet.
        FD_CLR(s->socket(), &socket_set);
        delete (*i);
        i = sockets.erase(i);
        if (i == sockets.end())
          break;
      }
    }
    clients.CheckForTimeout();
   //新来一个请求连接,将该socket加入监听集
    if (FD_ISSET(listener.socket(), &socket_set)) {
      DataSocket* s = listener.Accept();
     //select监听是个数超过最大值,忽略
      if (sockets.size() >= kMaxConnections) {
        delete s;  // sorry, that's all we can take.
        printf("Connection limit reached\n");
      } else {
        //否则加入socket队列
        sockets.push_back(s);
        printf("New connection...\n");
      }
    }
  }

这里面的main.cc是最顶层的业务逻辑,会调用data_socket.cpp和peer_channel.cpp,该data_socket负责http数据接收,数据解析,数据封装和响应回复。peer_channel负责房间ID的加入,查询等管理功能。至此整个peerconnection的demo分析完毕,后面我们将封装一个webrtc SDK提供给业务使用或根据需求定制webrtc的某些功能。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门