前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >webrtc之peerconnection_server详解

webrtc之peerconnection_server详解

作者头像
用户4148957
发布2022-06-14 09:04:06
5970
发布2022-06-14 09:04:06
举报
文章被收录于专栏:C/C++与音视频

     前面分析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 监控端口。

代码语言:javascript
复制
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进程的连接端口

代码语言:javascript
复制
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的某些功能。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档