大部分内容引自网络,感谢相关作者。
1,ssh转发X
这是最简单的方法,效率略低于adb转发。
手机proot安装系统完毕后,在容器系统中启动ssh服务器,PC端不能通过密码验证的原因是用户PAM验证,在/etc/sshd_config的配置文件中简单禁用PAM即可。同时保证/dev/pts目录的写入权限,sshd需要它。同时要知道termux只能自由使用8000以上端口,默认ssh端口是8022,登录同时转发X:
ssh -X user@IP -p 8022
#启用ssh压缩,需要修
#改/etc/ssh/sshd_config文件
#允许Compress,然后加C参数
ssh -X -C user@IP -p PORT
#scp同样加-C参数
scp -C user@IP:/xxx/PATH localdir
#scp传输同样需要指定端口
scp -P xxx user@IP:/path/to localehost
2,音频转发(不推荐)
在较早时候,ssh转发音频很简单,只需要执行下列命令:
ssh <username>@192.168.1.2 'dd
bs=1k if=/dev/audio' > /dev/audio
本质上,就是将音频输入设备(REMOTE)连接到音频输出设备(LOCAL),流块大小为1Kb。
当我们使用alsamixer命令时,按下F6键,我们可以看到系统拥有的所有声卡。
还可以使用下列命令:
arecord -f cd -t raw | oggenc - -r | ssh
<user>@<remotehost> mplayer -
ffmpeg -f alsa -ac 1 -i hw:3 -f ogg - \
| ssh <user>@<remotehost> mplayer - -idle -demuxer ogg
如果还要获得其它设备的连接,就需要重新启动一个ssh会话:
ssh <user>@<remotehost> 'arecord -f
cd -t raw | oggenc - -r' | mplayer -
或者使用ffmpeg:
ssh <user>@<remotehost> ffmpeg -f alsa -ac 1 -i hw:3 -f ogg - \
| mplayer - -idle -demuxer ogg
hw:3指要录音的设备(可以使用arecord -l命令得到,也可以使用设备名,使用arecord -L获得,获得系统默认设备arecord -L | grep sysdefault)。
如果没有alsa支持,那么这么做:
ssh <user>@<remotehost> 'arecord -f
cd -D plughw:2 | ffmpeg -ac 1 -i - -f
ogg -' \
| mplayer - -idle -demuxer ogg
plughw:3 同样由arecord找出来的。
mplayer也木有可以使用ffplay(只是ffmpeg的一部份):
- 未压缩wave音频,对于录音端,是高带宽(bandwidth),低cpu占用:
ssh <user>@<remotehost> "arecord
-f cd -D plughw:2" | ffplay -nodisp -
- flac压缩音频,录音端低带宽,低cpu占用:
ssh <user>@<remotehost> "arecord
-f cd -D plughw:2 | flac - -o
-" | ffplay -nodisp -
- ogg压缩音频,对于录音端,是低带宽,高cpu占用:
ssh <user>@<remotehost> "arecord
-f cd -D plughw:2 | oggenc
-" | ffplay -nodisp -
- 使用flac或oggenc可能有延迟,一个方法是指定mplay的缓冲区大小:
ssh <user>@<remotehost> "arecord -f cd -D plughw:2 | oggenc -" | mplayer -cache 256 -
现代发行版基本都使用PulseAudio来控制硬件设备,因此,当PulseAudio运行时,使用plughw:2会失败。一般情况下,使用PulseAudio默认的就可以了,可以采用pavucontrol命令选择输入源。
- 更简单的命令,兼容PulseAudio,极低cpu占用率:
ssh <user>@<host> "arecord -f S16_LE -r 36000" | aplay
- 使用立体声,需要录音端支持,大约增加150HZ带宽(相比44100Hz):
ssh <user>@<host> "arecord -f cd" | aplay
3,Pulseaudio音频服务器(推荐)
PC端配置Pulseaudio服务器,首先安装paprefs工具来配置网络音频访问,然后在服务端/etc/pulse/default.pa文件中插入一行语句:
load-module module-native-protocol-
tcp auth-ip-
acl=192.168.1.1/24;127.0.0.1
auth-anonymous=1
有些情况下,pulseaudio不读取默认文件,则需要手动载入模块。
可能需要打开防火墙相应(默认4713)端口。
4,远程X Server(备查)
可以通过以下命令查看运行的X Server桌面号:
ps -aux|grep Xorg
#或者
echo $DISPLAY
传统上,X Server监听TCP 6000端口,可能需要再防火墙打开该端口,现在系统启动时加了-nolisten tcp,需要去掉这个选项。在使用gdm3的系统中,可以修改/etc/gdm3/daemon.conf文件:
DisallowTCP=false,然后重启gdm3。
- 看是否取消TCP监听:
ps axuf|grep Xorg
- 查看是否监听6000端口
netstat -anp | grep 600
客户端需要设置$DISPLAY变量,指向服务器的地址,例如:
echo DISPLY=IP:桌面号
出于一般的安全考虑,默认不允许直接访问X,需要使用xhost命令添加客户端,例如:
xhost + 192.168.1.5
#然后查看一下允许的客户端:
xhost
由于上层存在不同的窗口管理器,可能还需要修改相应的配置方式。
5,Xauth设置(备查)
Xauth是半安全连接,远程服务器直接访问本地X Server会被阻止。因此需要设置Xauth。
Xauth显示规范采用了一种称为"magic cookie"的证书方式,客户端需要提交这个"cookie"给服务端。
Xauth默认配置使用环境变量$XAUTHORITY指向的文件或者用户目录下的.Xauthority文件。
#为桌面1,生成cookie
xauth
xauth>generate :1
#显示生成的key,一串十六进制
#32位明文密钥
#即所谓'MIT-MAGIC-COOKIE-1'
xauth>list
#X-Client端配置对显示 :1的访问密钥
xauth add IP:1 xxxx...xxxx
#配置终端使用远端桌面
export DISPLAY=IP:1
如果要编辑指定Xauthority文件,则执行xauth -f xxx命令。
另外一种ssh方式混合秘钥:
ssh IP xauth
extract - IP:1 | xauth merge -
检查是否能显示于本地机器:
xclock -display IP:桌面号
6,xhost不安全方式(实验用)
默认情况下,XServer关闭tcp端口,因此需要重开一个Xorg。
linuxmint mate下:
按ctrl+alt+f1打开一个tty,启动一个Xorg:
#打开tcp监听,并指向vt8虚拟tty
sudo X :1 -listen tcp vt8
X其实是一个Xorg命令的封装脚本。
按ctrl+alt+f7回已登录桌面,虚拟终端下启动一个mate-session:
dbus-launch mate-session --display=:1
这里要使用dbus作为进程间通信服务,否则无法正常启动mate桌面。
如果没有错误,按ctrl+alt+f8就可以看到mate桌面已经启动了。
打开新开桌面的虚拟终端,基于IP验证登录:
#取消访问控制和安全验证,非必须
xhost + access control disable,clients
can connect from any host
#添加客户机地址,必须
xhost + ip
#查看是否正确
xhost
如需重启后仍然生效,需要写入/etc/X[n].hosts文件,其中n为桌面号。
查看是否监听了6001端口,如果桌面号是2,XServer会在6002端口监听。以此类推。
netstat -aup|grep 600
可以看到XServer对6001端口监听了。
最后在防火墙打开6001端口,允许数据进入。
最后在客户机正常设置$DISPLAY变量即可。
如果不新开X,那么需要确定使用的桌面管理器,比如lightdm和gdm,如果是lightdm,修改/etc/lightdm下X启动相关配置文件,其中加入字段:
[SeatDefaults]
xserver-allow-tcp=true
查看使用什么窗口管理器,可以查看下X服务器的进程:
ps -aux|grep X
gdm则添加如下字段:
[security]
DisallowTCP=false
然后可能还要修改/etc/X11/xinit/xserverrc:
exec /usr/bin/X -nolisten tcp "$@"
#改成
exec /usr/bin/X -listen tcp
默认情况下监听6000端口。
还有一种xhost关闭安全验证的简写方法:
xhost +
即默认允许所有客户机访问。
7,协议NAT(nat-sensitive)敏感
NAT敏感 通常是因为协议的应用报文中
带有对端的IP信息, 对端在处理应用逻辑里
需要依赖这IP信息. 然而对端在NAT环境后
面(即做了DNAT, 外网IP映射为内网IP), 本
端是不知道你是做了DNAT的, 所以带的对
端的IP是对端的外网IP, 这时对端解释到
的IP信息是外网IP, 但他应用逻辑是用内网
IP的, 因此导致应用逻辑上的混乱。
X-Server与X-Client之间的远程通信使用TCP方式, 在实际测试中发现X-Server和X-Client在同一个局域网内才能连接成功, X-Client连接NAT后的X-Server的话是不能成功的. 看来这协议是’NAT敏感’的. 解决方法通常是使用SSH隧道。
还有一个内容, 那就是XDM(X-Display-Manager), 他使用的是XDMCP协议, 走UDP177端口. 以后有机会再补充这块内容。
- 7.1, 结合SSH隧道运行远端GUI应用
为解决刚说的’NAT敏感’问题. 我们常常使用SSH隧道上的端口转发功能来绕过问题。
远端上的X-Client应用程序访问其本地SSH-Server开启的转发监听端口PORT1, SSH-Server将其在Port1在监听接入的数据通过已经建立好连接的SSH隧道转发到我们本地的SSH-Client, SSH-Client再将数据转发到本地X-Server所监听的TCP端口PORT2。
以PORT1为6010, PORT2为6002为例, 其SSH隧道建立及开启转发功能的连接命令为:
ssh -R 127.0.0.1:6010:127.0.0.1:6002
user@remotehost
ssh有个简洁的-X参数能自动根据环境配置以上转发参数及远端SSH终端的DISPLAY环境变量. 可以自行翻阅文档查看详情,这功能需要在SSH-Server开启’X11 Forwarding’选项,
这样一来就避开了’NAT敏感’的问题, 从X-Client看来他只是访问本地的X-Server, 从X-Server看来他只是接入本地的X-Client, 所有X层面上看到的IP都是127.0.0.1。
同时这个做法避开了X-Security的xauth远程主机验证,因为都认为是本地主机的访问,只需允许本地访问即可。
8,adb反向方式转发
大概是速度最快的方式。
- UDS方式,需要root(未测试)
adb reverse localabstract:0 localabstract
:0
所谓UDS,即“Unix domain socket”,即IPC,socket原本用于网络通讯,后来在其框架构建了一种IPC(inter-process communication),即称UDS。
- UDS命名空间
NAMESPACE_RESERVED :就是init.c中/dev/socket/下建立的socket文件。
NAMESPACE_FILESYSTEM:普通命名空间。
NAMESPACE_ABSTRACT:虚拟命名空间。
adb reverse使用方法查阅帮助文档即可。
- tcp方式,无需root
仍然需要打开X Server的tcp监听。
显示端执行:
adb reverse tcp:6000 tcp:6000
然后远程端设置好DISPLAY的桌面号,即可正常显示:
export DISPLAY=:0
有疑问可参考前面描述的内容。
9,MiraCast方式
效率最高,整个手机都可以镜像投屏,树莓派可以使用lazycast,延迟可控制在300毫秒。pc端scrcpy(非miracast),低传输率下100毫米延迟。其它实现没有使用过。
pulseaudio服务器脚本示例
#!/bin/sh
usage() {
echo'Usage: paserver {on}|{off}
exit 1
}
case "$1" in
on )
pactl load-module module-native-protocol-tcp \
auth-ip-acl="xxx.xxx.xxx.xxx/24;127.0.0.1" auth-anonymous=1
;;
off )
pactl unload-module module-native-protocol-tcp
;;
* )
usage
;;
esac