远程控制一台在内网中的设备

文章目录

前段时间 wanqian 师傅添置了一台树莓派作为服务器连接到实验室的内网网络环境中。这台树莓派上安装了 Ubuntu 操作系统并装有一个摄像头模块,可以使用 fswebcam 命令控制摄像头拍照。不过遗憾的是,树莓派上没有图形化界面,如果想要查看图片就必须将图片传输到其他设备上;树莓派上的相机模块是反的,要是想正常查看需要将图片旋转 180°;树莓派在一个内网环境中,如果我想在宿舍里连接树莓派则需要每天交 1 元钱网费。

拍照、旋转、上传

wanqian 师傅出于安全性的考虑,不希望我使用内网穿透控制树莓派拍照。所以,我只能让树莓派与我的云服务器单线联系。因此我想到让树莓派检测云服务器上的某个端口是否开放,若开放则自动执行拍照上传等一系列命令,所以有了下面一个脚本(路径为 /home/gdn/gwc/agwc.sh。下文为便于叙述,树莓派用 R 表示,云服务器用 S 表示,个人计算机用 PC 表示):

 1#!/bin/bash
 2CONN='nc -zv IP_S 8963'
 3while true
 4do
 5        if $CONN ; then
 6                time=$(date +"%Y-%m-%d_%H-%M-%S")
 7                fswebcam --no-banner -r 1920x1080 /home/gdn/gwc/fagwc/$time.jpg
 8                convert /home/gdn/gwc/fagwc/$time.jpg -rotate 180 /home/gdn/gwc/fagwc/$time.jpg
 9                nc -v IP_S 8965 < /home/gdn/gwc/fagwc/$time.jpg
10        fi
11        sleep 10
12done

该脚本在 R 上运行,每隔十秒钟就会检测一次 S 的 8963 端口是否开放,如果开放,则使用 fswebcam 命令拍照,使用 convert 命令(在 ImageMagisk 工具集中)旋转图片并将图片使用 netcat 传输到 S 的 8965 端口上去。由于 netcat 连接特性,开放两个端口是必需的。另外,#! 的shebang 不能缺失,因为如果我们想将它写入 .service 文件自动运行,shebang 可以告诉计算机执行该脚本的解释器是什么。

利用 systemd 自动执行

下面的服务文件(路径为 /etc/systemd/system/agwc.service)用于自动执行该脚本:

1[Unit]
2Description=Autonomous Gideon-watching Client
3After=NetworkManager.service
4
5[Service]
6ExecStart=/home/gdn/gwc/agwc.sh
7
8[Install]
9WantedBy=multi-user.target

有了这个脚本,前面的 agwc.sh 就会在开机后自动运行。只需执行 sudo systemctl daemon-reloadsudo systemctl enable agwc.service,在下次树莓派开机时,这个服务就可以自动运行了。

配置服务器接受图片

下面需要配置服务端,需要让 S 能在我需要的时候开放端口,接收图片然后关闭端口。下面这一脚本的路径为 /home/USER_S/gdnwatch.sh

 1sudo firewall-cmd --zone=public --add-port=8963/tcp --permanent
 2sudo firewall-cmd --zone=public --add-port=8965/tcp --permanent
 3sudo firewall-cmd --reload
 4time=$(date +"%Y-%m-%d_%H-%M-%S")
 5nc -vl 8963 &
 6nc -vl 8965 > ~/pictures/$time.jpg &
 7sleep 10
 8ps aux | grep 'nc -vl 8963' | grep -v grep | awk '{print $2}' | xargs kill -9
 9ps aux | grep 'nc -vl 8965' | grep -v grep | awk '{print $2}' | xargs kill -9
10sudo firewall-cmd --zone=public --remove-port=8963/tcp --permanent
11sudo firewall-cmd --zone=public --remove-port=8965/tcp --permanent
12sudo firewall-cmd --reload
13find ./pictures/ -size -1b -exec rm {} \;

这一脚本在 S 上运行。脚本首先将 8963 与 8965 端口打开并监听这两个端口并等待十秒,这两个端口分别用于标志和接受文件。接收到文件后,脚本会将两个 netcat 进程关闭以便于下次能够继续使用 netcat 监听这两个端口。再然后,关闭 8963 与 8965 两个端口。在某些情况下(例如 R 没有开机),S 接收不到任何信息并创建一个空文件,这时就需要将文件大小小于 1B 的图片删除。

传输到个人计算机上浏览图片

进行到这一步,只剩下最后一个问题没有解决,就是浏览图片。S 上没有远程桌面,我不能在 S 上查看这些图片,我只能再将图片传输到 PC 上查看。因此,我们在 PC 上创建下面这个脚本(get-pictures.cmd,在 Linux 系统上将后缀改为 .sh 同样可以运行):

1ssh USER_S@IP_S "bash ~/gdnwatch.sh"
2sftp USER_S@IP_S:pictures/* C:\Users\jack_gdn\Pictures\Raspberry-Pi\pictures\
3ssh USER_S@IP_S "find ~/pictures/ -name '*.*' -exec rm {} \;"

这个脚本控制 S 运行 gdnwatch.sh 脚本,随后自动将图片传输回 PC,并且删除 S 上的图片缓存以节省存储空间。

至此,我只需要在 PC 上运行 get-pictures.cmd 脚本就可以坐等图片传输回 PC 了。当然,既然使用了 SSH 与 SFTP,那么 ssh-genkey -t rsassh-copy-id 实现免密码登录必不可少。上面这种远程拍照方式会使 S 每月额外消耗大约 170M 流量。