首页
学习
活动
专区
圈层
工具
发布

SpringBoot+WebSocket 实现直播连麦

前几天在我们组那个小黑工位那块,聊着直播那点事儿,正好他说他们最近在搞一个类似声网的那种连麦功能,用的是 SpringBoot 加 WebSocket。我一听就精神了,赶紧扒着他那块儿的屏幕看,因为这玩意儿以前我只搞过聊天室,真到直播连麦还没整过。

说白了,这事儿没你想的那么玄乎,关键就两个东西:一个是 WebSocket 实时通信,一个是前后端如何“配合演得像”,你得让人感觉是真在连麦,说话就能听到。

咱先说服务端怎么搭

我就说我看到的那一段代码啊,没拍照但脑子还清楚。首先,SpringBoot 那边 WebSocket 开启是这样的:

@Configuration

@EnableWebSocket

public class WebSocketConfig implements WebSocketConfigurer {

  @Override

  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

      registry.addHandler(new LiveWebSocketHandler(), "/ws/live")

              .setAllowedOrigins("*");

  }

}

这个/ws/live是 WebSocket 的入口,连麦时候前端就会连这个地址,一进来后端就把你这个 session 给存起来。用一个 map 存的,key 是用户 ID,value 是 session。

我当时问他,"你怎么处理两个人连麦的绑定啊?" 他说是靠用户点击“连麦”按钮之后发一条 JSON 消息,里面带了目标主播的 ID,后端解析后把两个用户 session 对上。

那消息来回咋整呢?

这里头最骚的地方就是消息分发。就我看那段代码,他是这么写的:

@Override

public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {

  String payload = message.getPayload();

  JSONObject json = JSON.parseObject(payload);

  String type = json.getString("type");

  if ("invite".equals(type)) {

      String targetUser = json.getString("targetUser");

      WebSocketSession targetSession = sessionMap.get(targetUser);

      if (targetSession != null && targetSession.isOpen()) {

          targetSession.sendMessage(new TextMessage("你被邀请连麦啦~"));

      }

  }

}

你看这逻辑就很直,谁点了连麦,后端就把这消息甩给对方,那边就弹个窗口出来:"XXX想和你连麦"。

音视频数据不走这条线

我一开始以为音频也靠 WebSocket 传,后来小黑直接瞪我一眼:"哥你清醒点,WebSocket 哪能扛得住音视频的压力,我们那是前端用 WebRTC 通信的,WebSocket 只传控制信息"。

对,这也是重点。你真想做连麦,不是说你把两个 socket 对上就完事儿了,那样顶多是个文字聊天室。音视频部分,WebRTC 走的是另一套协议,浏览器之间 P2P 通道建立好后,数据就不经后端了,节省延迟和带宽。

WebSocket 干嘛的?就是负责这些动作的协调,比如:

用户A发起连麦请求

用户B接受连麦

某一方挂断了

服务器踢人或者掉线了

就全靠这个 handler 来“吆喝”大家同步动作。

我还看到一段心跳检测的

这个也挺重要的,特别直播时间一长,连接很容易断。他们就每隔 30 秒前端发条"ping",后端回"pong",如果一段时间没收到就把 session 踢了。

@Override

public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {

  String payload = message.getPayload();

  if ("ping".equals(payload)) {

      session.sendMessage(new TextMessage("pong"));

      return;

  }

  // 其他逻辑略

}

其实这玩意儿跟你做游戏服差不多,要保证连接稳定,实时性高。

最后说说踩过的坑

小黑还跟我抱怨,说 SpringBoot 默认用的那套TomcatWebSocketSession有时候处理并发不太行,一堆并发 sendMessage 容易报错,所以他们后面还加了个锁,或者用队列异步发消息。

还有一个坑,就是浏览器断线以后你得监听onClose和onError,不然 sessionMap 里全是“死连接”,一旦重连你还以为人家在线,结果根本发不过去。

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

  // 找出用户ID,移除掉

  userSessionMap.entrySet().removeIf(entry -> entry.getValue().equals(session));

}

哎我说这么多主要是最近也想着要不把我以前那个聊天室系统重构一下,改成能连麦那种,技术上其实不难,主要就是协调逻辑麻烦。你说一个主播连两个用户,那怎么混流?怎么同步?这都得琢磨。

不过等我这两天项目告一段落,准备撸个 demo 玩玩,谁要是也整了这个方向,喊我一声,咱们搞点联动不香吗?算了我先去泡杯茶,脑袋晕了。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OzYVkPo1OdOnB9m6PChlsZEA0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券