当前位置: 首页 > news >正文

实践教程:基于RV1126与ZeroTier的RTSP摄像头内网穿透与远程访问

一、 项目背景与目标 🎯

我手上有一块RV1126的开发板,外接了一个SunplusIT SPCA2688 USB摄像头。我的目标是搭建一个可以从任何地方远程访问的实时监控系统。

初始本地推流实现(详细教程请参考RV1126平台(Buildroot Linux)+ SunplusIT SPCA2688 USB摄像头 RTSP推流全流程复盘与问题解决记录-CSDN博客

首先,我在开发板上成功实现了局域网内的RTSP推流。我使用的是 MediaMTX 作为RTSP服务器,并用 FFmpeg 来捕获摄像头数据、进行编码,然后推送到MediaMTX

我将所有命令都写在了一个脚本 rtsp_usb_camera_test.sh 中,方便一键启动。脚本内容如下

#!/bin/sh# 启动 MediaMTX RTSP 服务器,并在后台运行
/mediamtx_v1.13.0_linux_armv7/mediamtx &# 等待3秒,确保服务器已完全启动
sleep 3# 使用 FFmpeg 从v4l2设备捕获视频,用libx264软编码,并推送到本机的RTSP服务器
ffmpeg -f v4l2 -input_format mjpeg -video_size 640x480 -framerate 15 -i /dev/video45 \
-c:v libx264 -preset ultrafast -tune zerolatency \
-f rtsp -rtsp_transport tcp rtsp://127.0.0.1:8554/live/main_stream

在开发板上运行这个脚本后,我可以在同一个WiFi下的电脑或手机上,用VLC播放器打开地址 rtsp://192.168.1.16:8554/live/main_stream 来观看实时监控画面。

这一切在家里用起来很方便,但我萌生了一个新想法:我希望能随时随地,无论是在公司、在路上还是在朋友家,都能看到这个摄像头的画面。

我的核心目标是:

  1. 实现公网远程访问。

  2. 方案必须是永久免费的。

  3. 要足够稳定可靠。

二、 方案选择:为什么是ZeroTier

经过一番了解,我发现有几种主流方案,比如“公网IP+DDNS+端口转发”、“FRP内网穿透”等。但这些方案要么依赖运营商提供公网IP,要么需要自己有一台云服务器,都有些门槛。

最终,我选择了 ZeroTier。它的理念深深吸引了我:创建一个“虚拟的局域网”,把我所有的设备(开发板、手机、电脑)都连接到这个虚拟网络里。设备之间就像真的在同一个路由器下一样,可以通过虚拟IP直接通信。最关键的是,它的免费套餐对于个人使用来说完全足够,而且安全性很高,不需要把任何端口暴露在公网上。

三、 实施过程:一步步实现远程访问

我的计划很清晰:给开发板和我的手机都装上ZeroTier客户端,让它们“手拉手”,然后通过虚拟IP访问视频流。

  1. 注册和创建网络:我先去ZeroTier官网 my.zerotier.com 注册了一个账号,过程很简单。登录后,我点击“Create A Network”,系统立刻为我生成了一个16位的网络ID(Network ID),这个ID就是我虚拟局域网的唯一门牌号。

  2. 手机入网:我在手机上下载了ZeroTier One的App,输入网络ID,轻松加入了网络。并且在官网后台的“Members”列表里,给我的手机勾选了“Auth?”,批准了它的加入。手机很快就获得了一个10.144.x.x开头的虚拟IP。

  3. 在开发板上安装客户端:这是挑战的开始。我的RV1126是Buildroot制作的精简Linux系统,没有apt-get,连curl命令都没有。官方提供的一键安装脚本完全用不了。

  4. 攻克安装难关:我最终采用了最原始也最可靠的方法:

    • 在电脑上下载了ZeroTier的.deb安装包(armhf架构,兼容我的armv7l开发板)。

    • 在我的Ubuntu虚拟机里,用dpkg-deb -x命令解压这个.deb包,从中提取出了zerotier-one这个最核心的可执行文件。

    • zerotier-one文件从Ubuntu虚拟机传输到开发板。我使用的是 adb push 命令,这个方式对于连接了USB的开发板来说非常方便。

  5. 启动服务与最终连接:为了避免每次都手动敲大量命令,我编写了一个Shell脚本,将所有在开发板上需要执行的命令都整合了进去。这个脚本帮我完成了移动文件、设置权限、创建开机自启服务、启动服务、并最终加入网络的所有操作。下面是这个脚本的完整内容:

    #!/bin/sh# 任何命令失败则立即退出
    set -e# 清理旧的、可能存在的服务进程,防止端口占用
    killall zerotier-one >/dev/null 2>&1 || true# --- 欢迎与检查 ---
    echo "============================================="
    echo "===  ZeroTier 最终版安装脚本 (遵从指示)  ==="
    echo "============================================="
    echo "脚本将从 /root 目录读取文件,并安装到 /usr/bin 目录。"
    echo ""if [ ! -f "/root/zerotier-one" ]; thenecho "错误:在 /root 目录下未找到 'zerotier-one' 文件!"echo "请先将 zerotier-one 文件传输到 /root 目录再运行。"exit 1
    fi# --- 获取 Network ID ---
    echo "请输入您的16位 ZeroTier Network ID,然后按回车:"
    read NETWORK_ID
    if [ -z "$NETWORK_ID" ]; thenecho "错误:Network ID 不能为空!"exit 1
    fi# --- 开始安装 ---
    echo ""
    echo "--- 步骤 1/5: 移动文件到 /usr/bin 并创建链接 ---"
    mv /root/zerotier-one /usr/bin/
    ln -sf /usr/bin/zerotier-one /usr/bin/zerotier-cli
    echo "✅ 完成"echo "--- 步骤 2/5: 设置文件执行权限 ---"
    chmod +x /usr/bin/zerotier-one
    echo "✅ 完成"echo "--- 步骤 3/5: 创建数据目录 ---"
    mkdir -p /var/lib/zerotier-one
    echo "✅ 完成"echo "--- 步骤 4/5: 创建开机自启服务 ---"
    # 注意:这里的路径已更正为 /usr/bin/zerotier-one
    cat > /etc/init.d/S99zerotier << EOF
    #!/bin/sh
    start() {echo "Starting ZeroTier One..."/usr/bin/zerotier-one -d
    }
    stop() {echo "Stopping ZeroTier One..."PID=\$(ps | grep '[z]erotier-one' | awk '{print \$1}')if [ ! -z "\$PID" ]; then kill \$PID; fi
    }
    case "\$1" instart) start ;;stop) stop ;;restart) stop; start ;;*) echo "Usage: \$0 {start|stop|restart}"; exit 1 ;;
    esac
    exit 0
    EOF
    chmod +x /etc/init.d/S99zerotier
    echo "✅ 完成"echo "--- 步骤 5/5: 启动服务并加入网络 ---"
    /etc/init.d/S99zerotier start
    sleep 3
    zerotier-cli join "$NETWORK_ID"
    echo "✅ '加入网络' 请求已发送!"
    echo ""# --- 最终提示 ---
    echo "======================================================"
    echo "🎉 恭喜!脚本执行完毕!"
    echo "🚨【 最后一步,非常重要!】🚨"
    echo "请立即登录 ZeroTier 官网后台 (my.zerotier.com),"
    echo "找到这台新设备,并把它前面的复选框打勾授权!"
    echo "======================================================"

    6.最终测试:在经历了一系列问题的排查后,我在开发板上运行zerotier-cli listnetworks,终于看到了梦寐以求的虚拟IP!然后,我在手机VLC里,输入了 rtsp://<开发板的虚拟IP>:8554/live/main_stream,看到了清晰的画面。成功!

四、 遇到的问题与解决方案(踩坑全记录)🚧

这段旅程并非一帆风顺,我遇到了大大小小9个问题。正是解决了这些问题,才让我对嵌入式Linux和网络知识有了更深刻的理解。

问题1:开发板系统太精简,无法自动安装
  • 现象: 在开发板上想用apt-getcurl一键安装ZeroTier,结果提示command not found

  • 原因分析: 我的RV1126是Buildroot构建的,为了追求极致的性能和最小的体积,系统里没有包含这些包管理器和下载工具。

  • 解决方案: 手动部署。最终采用的方法是:在电脑上下载适配ARM架构的.deb包,在Ubuntu虚拟机中用dpkg-deb -x命令解压,从中提取出zerotier-onezerotier-cli这两个最核心的可执行文件,再通过adb push命令传输到开发板上。

问题2:在官网和GitHub上找不到预编译包
  • 现象: 按照一些教程去ZeroTier官网或GitHub Releases页面下载,发现 .tar.gz 格式的通用二进制文件都消失了,只有源代码。

  • 原因分析: ZeroTier官方调整了发布策略,不再提供显式的通用二进制包下载,这给非主流发行版的用户带来了困难。

  • 解决方案: 曲线救国。既然找不到通用包,我就去找特定发行版(Debian)的包。我从下面的地址下载了armhf架构的.deb包,这成为了后续提取文件的基础。

    下载地址: https://download.zerotier.com/dist/debian/bullseye/zerotier-one_1.12.2_armhf.deb

问题3:解压.deb包时,提示符号链接创建失败
  • 现象: 在Ubuntu虚拟机里解压.deb包时,报错tar: ... Cannot create symlink: Operation not supported

  • 原因分析: 我当时偷懒,直接在Windows和Ubuntu的共享文件夹(VMware的hgfs)里进行解压。Windows的NTFS文件系统原生不支持Linux的符号链接(symlink),导致解压失败。

  • 解决方案: 更换工作目录。将.deb文件从共享文件夹复制到Ubuntu自己的主目录(~/)下,这里的ext4文件系统完美支持所有Linux特性,再执行解压命令,问题解决。

问题4:启动服务时,报错端口9993被占用
  • 现象: 运行启动命令后,报fatal error: cannot bind to local control interface port 9993。但用ps命令又可能看不到zerotier-one进程。

  • 原因分析: 这是个“假死”现象。很可能是之前的进程异常崩溃,但它占用的网络端口没有被内核及时释放,成了一个“僵尸端口”。

  • 解决方案: 精准定位并强行终止。使用netstat -anp | grep 9993命令,它能无视进程状态,直接查出是哪个进程ID(PID)占用了该端口。然后使用kill -9 <PID>命令,将这个“幽灵”进程彻底杀死,从而释放端口。

问题5:启动服务时,报错找不到TUN/TAP设备
  • 现象: 解决了端口问题后,又出现新错误could not open TUN/TAP device: No such file or directory

  • 原因分析: 这是个更底层的系统问题。意味着我的Linux内核在编译时,就没有包含“虚拟网卡”(TUN)这个功能。ZeroTier依赖此功能才能工作。

  • 解决方案: 重新编译内核。我回到了Buildroot开发环境,执行make linux-menuconfig,进入内核配置菜单。按照路径Device Drivers -> Network device support,找到了Universal TUN/TAP device driver support选项,并将其设置为y<*>,直接编译进内核),然后重新make生成新固件并烧录。

问题6:加入网络后,无法获取虚拟IP
  • 现象: 在开发板上执行zerotier-cli join <nwid>后返回200 join OK,但listnetworks命令的结果一直只有表头,没有任何网络信息。

    # 解决前
    [root@ATK-DLRV1126:~]# zerotier-cli listnetworks
    200 listnetworks <nwid> <name> <mac> <status> <type> <dev> <ZT assigned ips>
  • 原因分析: 设备发出“敲门”请求后,我作为“房主”,没有在ZeroTier官网后台批准它进门。

问题7:远程视频画面花屏、卡顿严重
  • 现象: 手机在4G网络下终于能看到画面了,但画质极差,满屏的马赛克和色块,根本无法正常观看。用zerotier-cli peers诊断,看到了RELAY状态

    # 解决前
    [root@ATK-DLRV1126:/]# zerotier-cli peers
    200 peers
    <ztaddr>     <ver>  <role> <lat> <link>   <lastTX> <lastRX> <path>
    0678ebc45f -      LEAF     -1 RELAY
    ...
  • 原因分析: 我的手机和开发板之间的连接模式是RELAY(中继),而不是DIRECT(直连)。数据通过服务器中转,延迟和带宽都极差,无法承载视频流。

  • 解决方案: 优化网络,打通直连路径。我登录到开发板连接的路由器(天翼网关)后台,在“高级设置” -> “端口映射”功能里,为开发板的局域网IP(192.168.1.16)添加了一条规则,将UDP协议的9993端口转发出去。

    • 虚拟服务名称: ZeroTier

    • 局域网IP: 192.168.1.16

    • 服务协议: UDP

    • 内部端口: 9993

    • 外部端口: 9993

      # 解决后
      [root@ATK-DLRV1126:/]# zerotier-cli peers
      200 peers
      <ztaddr>     <ver>  <role> <lat> <link>   <lastTX> <lastRX> <path>
      632ea29085 1.14.2 LEAF    265 DIRECT   4459     13116    35.209.122.2/28655
      ...
问题8:手机使用移动数据时无法连接ZeroTier
  • 现象: 手机关掉WiFi用流量,ZeroTier App的连接开关打不开,并提示Not on Wi-Fi...

  • 原因分析: ZeroTier App为了防止误耗用户流量,默认设置只在Wi-Fi下工作。

  • 解决方案: 修改App设置。在ZeroTier App的设置(右上角三个点)里,找到Use Mobile Data(允许使用移动数据)选项,并将其开启。

问题9:远程播放时,局域网无法同时观看
  • 现象: 当手机通过ZeroTier观看视频时,局域网内的另一台电脑用VLC就无法打开视频流了。

  • 原因分析: 性能瓶颈。我的ffmpeg命令使用的是CPU进行软件编码(libx264),这本身就消耗了大量CPU资源。当MediaMTX服务器需要同时服务两条视频流(一条给ZeroTier,一条给局域网)时,开发板的CPU和网络I/O不堪重负,导致无法响应新的连接请求。

  • 解决方案: 承认性能极限。对于RV1126这样的嵌入式设备,同时进行实时编码和多路网络分发是一项沉重的任务。这个问题暂时作为性能极限来接受。后续优化的方向可以是利用硬件编码来解放CPU,或者降低视频流的码率和分辨率。

五、最终成果与感悟

经历了上述所有挑战后,我终于实现了最初的目标。现在,无论我身在何处,只要手机有网络,就能随时打开VLC,输入 rtsp://10.144.66.102:8554/live/main_stream,看到家里的实时画面。

这个过程虽然曲折,但每解决一个问题,都让我对Linux系统、网络知识和解决问题的思路有了新的认识。从一个简单的需求出发,最终完成了一个可靠、免费、安全的个人项目,这种成就感无与伦比。希望我的这份记录,能为后来的朋友们照亮前路,少走一些弯路。

最终实现效果图:

http://www.dtcms.com/a/289861.html

相关文章:

  • InfluxDB 数据模型:桶、测量、标签与字段详解(一)
  • iptables -m connlimit导致内存不足
  • 数据存储方案h5py
  • jdk9 -> jdk17 编程方面的变化
  • Product Hunt 每日热榜 | 2025-07-20
  • Feign远程调用
  • LWJGL教程(2)——游戏循环
  • VMware中mysql无法连接端口3306不通
  • 暑假训练之动态规划---动态规划的引入
  • PrimeTime:高级片上变化(AOCV)
  • 1948. 删除系统中的重复文件夹
  • 16.TaskExecutor启动
  • Windows批量修改文件属性方法
  • pyhton基础【27】课后拓展
  • 【华为机试】169. 多数元素
  • C++ STL中迭代器学习笔记
  • day057-docker-compose案例与docker镜像仓库
  • 元学习算法的数学本质:从MAML到Reptile的理论统一与深度分析
  • Vision Transformer (ViT) 介绍
  • 面试高频题 力扣 417. 太平洋大西洋水流问题 洪水灌溉(FloodFill) 深度优先遍历(dfs) 暴力搜索 C++解题思路 每日一题
  • 使用unsloth模型微调过程
  • 软件反调试(5)- 基于注册表实时调试器检测
  • MYSQL:从增删改查到高级查询
  • 数据结构-线性表的链式表示
  • 《P3398 仓鼠找 sugar》
  • 【1】YOLOv13 AI大模型-可视化图形用户(GUI)界面系统开发
  • 【实证分析】会计稳健性指标分析-ACF、CScore、Basu模型(2000-2023年)
  • MySQL锁(二) 共享锁与互斥锁
  • Filter快速入门 Java web
  • Compose笔记(三十七)--FilterChip