You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于DigitalOcean VPS搭建WebSocket中继服务器实现跨网设备实时通信?

实现跨网络WebSocket视频中继的完整方案

嘿,我来帮你一步步搞定这个跨设备WebSocket视频传输的问题!你的思路完全正确——用DigitalOcean VPS做中继服务器,让两边设备主动连它,完美绕过端口转发的限制。下面是具体的实现步骤,都是实际测试过可行的方案:

一、核心架构确认

我们要实现的是:
Chrome设备A ↔ VPS WebSocket中继服务器 ↔ 树莓派设备B
两边设备都主动连接VPS的公网WebSocket服务,VPS负责把A和B的消息互相转发,这样就能实现实时视频流传输了。

二、VPS端部署WebSocket中继服务器

我推荐用Node.js来写中继,因为它对实时通信支持很好,代码也简单:

  1. 先在VPS上安装Node.js和npm
    登录你的DigitalOcean droplet,执行命令:

    sudo apt update && sudo apt install nodejs npm -y
    
  2. 编写中继服务器代码
    创建一个relay-server.js文件,内容如下:

    const WebSocket = require('ws');
    // 监听8080端口,也可以改成你喜欢的端口
    const wss = new WebSocket.Server({ port: 8080 });
    
    // 用来存储两个设备的连接实例
    const connections = {
      deviceA: null,
      deviceB: null
    };
    
    wss.on('connection', (ws) => {
      // 第一步:让设备发送身份标识(deviceA/deviceB)来区分
      ws.on('message', (data) => {
        const msg = data.toString().trim();
        if (msg === 'deviceA' || msg === 'deviceB') {
          connections[msg] = ws;
          console.log(`✅ 设备${msg}已连接`);
          return;
        }
    
        // 第二步:转发消息——A发的给B,B发的给A
        if (connections.deviceA && connections.deviceB) {
          if (ws === connections.deviceA) {
            connections.deviceB.send(data);
          } else if (ws === connections.deviceB) {
            connections.deviceA.send(data);
          }
        }
      });
    
      // 处理设备断开的情况,清理连接
      ws.on('close', () => {
        if (ws === connections.deviceA) {
          console.log(`❌ 设备deviceA已断开`);
          connections.deviceA = null;
        } else if (ws === connections.deviceB) {
          console.log(`❌ 设备deviceB已断开`);
          connections.deviceB = null;
        }
      });
    });
    
    console.log(`🚀 WebSocket中继服务器已启动,监听端口8080`);
    
  3. 安装依赖并启动服务器
    执行下面的命令初始化项目、安装WebSocket库:

    npm init -y
    npm install ws
    

    启动服务器:

    node relay-server.js
    

    为了让服务器后台运行(避免关闭终端就停止),可以用pm2:

    sudo npm install -g pm2
    pm2 start relay-server.js
    pm2 save  # 设置开机自启
    
  4. 开放VPS防火墙端口
    如果你的VPS用的是ufw防火墙,执行命令开放8080端口:

    sudo ufw allow 8080/tcp
    sudo ufw reload
    

三、树莓派(Device B)端代码:发送视频流

树莓派需要主动连接VPS的WebSocket服务,把摄像头采集的视频帧发送给中继服务器。这里用Python实现:

  1. 安装依赖库

    pip install websockets picamera2 opencv-python-headless
    
  2. 编写视频发送代码(比如video-sender.py)

    import asyncio
    import websockets
    from picamera2 import Picamera2
    import cv2
    import numpy as np
    
    # 替换成你的VPS公网IP
    VPS_WS_URL = 'ws://你的VPS公网IP:8080'
    
    async def send_video_stream():
        async with websockets.connect(VPS_WS_URL) as websocket:
            # 先发送身份标识,告诉中继服务器我是deviceB
            await websocket.send('deviceB')
            print("已连接到中继服务器,开始发送视频流...")
    
            # 初始化摄像头
            picam2 = Picamera2()
            # 配置分辨率和格式,分辨率越小传输越流畅
            picam2.configure(picam2.create_preview_configuration(
                main={"format": 'RGB888', "size": (640, 480)}
            ))
            picam2.start()
    
            try:
                while True:
                    # 采集摄像头帧
                    frame = picam2.capture_array()
                    # 把帧转成JPEG格式(压缩后体积更小,适合实时传输)
                    _, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 70])
                    # 发送二进制数据
                    await websocket.send(buffer.tobytes())
                    # 控制帧率,这里设为30帧/秒
                    await asyncio.sleep(1/30)
            except Exception as e:
                print(f"发送出错: {e}")
            finally:
                picam2.stop()
                print("已停止视频发送")
    
    if __name__ == '__main__':
        asyncio.run(send_video_stream())
    
  3. 运行代码

    python video-sender.py
    

四、Chrome浏览器(Device A)端:接收并显示视频流

写一个简单的HTML页面,在Chrome里打开就能接收视频流:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>树莓派视频流</title>
</head>
<body>
    <h2>来自树莓派的实时视频</h2>
    <img id="video-img" style="width: 640px; border: 1px solid #ccc;" />

    <script>
        // 替换成你的VPS公网IP
        const VPS_WS_URL = 'ws://你的VPS公网IP:8080';
        const ws = new WebSocket(VPS_WS_URL);
        const imgElement = document.getElementById('video-img');

        ws.onopen = () => {
            // 发送身份标识,告诉中继服务器我是deviceA
            ws.send('deviceA');
            console.log("已连接到中继服务器");
        };

        ws.onmessage = (event) => {
            // 把收到的二进制数据转成Blob,生成URL显示在图片标签里
            const blob = new Blob([event.data], { type: 'image/jpeg' });
            imgElement.src = URL.createObjectURL(blob);
        };

        ws.onclose = () => {
            console.log("与中继服务器断开连接");
        };

        ws.onerror = (error) => {
            console.error("连接出错:", error);
        };
    </script>
</body>
</html>

把这个HTML文件保存为video-viewer.html,在Chrome里打开即可看到树莓派传来的实时视频。

五、优化与注意事项

  • 视频流畅度优化:如果出现卡顿,可以降低摄像头分辨率(比如改成480x360)、调低JPEG压缩质量(代码里的70可以改成50-60),或者减少帧率。
  • 安全升级:如果要在公网长期使用,建议用WSS(加密WebSocket),给VPS申请Let's Encrypt SSL证书,然后把服务器改成监听443端口,代码里的ws改成wss。
  • 连接稳定性:可以在两边的代码里添加重连逻辑,比如断开后自动尝试重新连接。
  • 关于你之前的疑问:你之前想让VPS监听树莓派的本地IP,其实完全不需要——因为树莓派在局域网内,VPS没法主动访问它,正确的做法是让树莓派主动连接VPS的公网服务,这也是上面方案的核心逻辑。

内容的提问来源于stack exchange,提问作者Shariq Azim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:36:15