本篇文章没有太多的源码,主要讲一下实现思路和技术原理
当使用Xshell或者SecureCRT终端工具时,我的所有文件传输工作都是通过lrzsz
来完成的,主要是因为其简单方便,不需要额外打开sftp之类的工具,通过命令就可轻松搞定,在用了WebSSH之后一直在想,这么便捷的操作WebSSH能够实现吗?
答案是肯定的,能实现!这要感谢这个古老的文件传输协议:zmodem
zmodem采用串流的方式传输文件,是xmodem和ymodem协议的改良进化版,具有传输速度快,支持断点续传、支持完整性校验等优点,成为目前最流行的文件传输协议之一,也被众多终端所支持,例如Xshell、SecureCRT、item2等
优点之外,zmodem也有一定的局限性,其中之一便是只能可靠地传输大小不超过4GB的文件,但对于大部分场景下已够用,超大文件的传输一般也会寻求其他的传输方式
lrzsz就是基于zmodem协议实现的文件传输,linux下使用非常方便,只需要一个简单的命令就可以安装,例如centos系统安装方式如下
yum install lrzsz
安装完成后就可以通过rz
命令上传文件,或者sz
命令下载文件了,这么说上传或下载其实不是很准确,在zmodem协议中,使用receive接收和send发送来解释更为准确,无论是receive还是send都是由服务端来发起的
rz
的意思为recevie zmodem,服务端来接收数据,对于客户端来说就是上传
sz
的意思是send zmodem,服务端来发送数据,对于客户端来说就是下载
文件的传输需要服务端和客户端都支持zmodem协议,服务端通过安装lrzsz实现了对zmodem协议的支持,Xshell和SecureCRT也支持zmodem协议,所以他们能通过rz或sz命令实现文件的上传和下载,那么Web浏览器要如何支持zmodem协议呢?
我们所使用的终端工具xterm.js在3.x版本提供过zmodem扩展插件,但很可惜在4.x版本中已经停止支持了,还好给xterm.js提供zmodem扩展插件的作者开源了一个项目:zmodemjs,用来提供浏览器Web对zmodem协议的支持,且能很好的跟xterm.js工具相结合,有了zmodemjs我们就可以通过浏览器与终端交互,调用系统rzsz命令实现文件上传下载了
需要注意的是zmodem是个二进制协议,只支持二进制流,所以通过websocket传输的数据必须是二进制的,在django的channel中可以通过指定发送消息的类型为bytes_data
来实现websocket传输二进制数据,这是后端实现的核心
websocket.send(bytes_data=data)
配合zmodemjs的前端实现,最终的效果如下
当我完成了Web上使用rzsz上传下载文件功能后,遇到了一个棘手的问题,无论是监控还是录像,在sz下载时会将下载的文件二进制显示在屏幕上,这主要是因为通过zmodemjs可以解析webssh中的二进制文件流为文件,而监控和录像不行解析,这就需要监控和录像时过滤掉文件二进制流,起初我想通过分析二进制流来判断这段流究竟是文件还是文本,但最后发现无法准确识别,一个稍微靠谱的方法是对binary流进行decode解码,但不能保证100%准确
又深入研究了zmodem协议是如何实现识别的,发现了zmodem的实现原理
在服务器上执行sz命令后,会先输出**B00000000000000
这样的内容,标识文件下载开始,当文件下载结束后会输出OO
,取这两个特殊标记之间的二进制流组合成文件,就是要下载的完整文件
rz命令类似,会在开始时输出rz waiting to receive.**0100000023be50
标记,知道了这个规则,就只需要在发送给监控和录像的数据中去除sz标记之间的内容就可以了,问题完美解决,算是给WebSSH系列画上了句号