Skip to content

在 WSL 中通过 Unix Domain Socket 启动图形应用

Martin Chloride edited this page May 18, 2019 · 1 revision

TL;DR

通过 AF_UNIX 与 X-Org 通信

  1. 在 Windows 上安装打过 AF_UNIX 补丁的 VcXsrv (X-Org 服务器的 windows 移植). 添加以下启动参数以使用 AF_UNIX: -listen unix.

  2. 在 WSL 上安装打过 AF_UNIX 补丁的 libxcb.

  3. 创建符号链接:/tmp/.X11-unix -> /mnt/c/tmp/.X11-unix.

  4. 在 WSL 中测试环境是否可用:DISPLAY=unix:0 gnome-terminal.

通过 AF_UNIX 与 PulseAudio 通信

  1. 在 Windows 上安装打过 AF_UNIX 补丁的 PulseAudio. 添加以下模块以使用 AF_UNIX:module-native-protocol-unix socket=C:\\tmp\\pulse\\pulse.sock auth-anonymous=1.

  2. 在 WSL 上安装打过 AF_UNIX 补丁的 libpulse.

  3. 在 WSL 中测试环境是否可用:PULSE_SERVER=/mnt/c/tmp/pulse/pulse.sock paplay -p /mnt/c/Windows/media/ding.wav

前言

在 Windows Subsystem of Linux 中使用图形应用已经不是什么新鲜事了。简单来说,Linux 上的图形应用会通过 X11 协议使用 X-Org 服务器来显示画面,并且通过使用 PulseAudio 服务器来播放声音。以为这套设计具有网络透明性,在 Windows 上也可以通过同样的架构运行。

一般来说 Linux 图形应用会使用 Unix Domain Socket (AF_UNIX) 与视频、音频服务器沟通。但是目前为止所有在 WSL 中使用图形应用的方案都使用了 TCP loopback(连接到 127.0.0.1 的 TCP 连接)通信。

Windows 10 自 1803 开始支持了 Unix Domain Socket,而更妙的是它还支持 Windows 与 WSL 之间的互访。因此,在 Windows 下通过 Unix Domain Socket 来与 X-Org 服务器和 PulseAudio 服务器通信是完全可行的。所以我自己做了一点移植来实现这个功能。

设置 Windows 上的服务端

VcXsrv

我使用了 VcXsrv 作为给 X-Org 打补丁的实现(要我说它和其他实现一样都是 XWin 的 fork)。以下是编译好的安装包:

完妆完成后通过以下命令启动 X-Org 服务器:

.\vcxsrv.exe -nolisten tcp -listen unix -multiwindow

这条命令会在 0 号显示端口启动服务器。启动完毕后可以通过以下方法验证是否可用:右键任务栏中的 X 图标,选择 Applications 然后启动 xcalc。如果运作正常的话你会看到一个计算器窗口。

一个坏消息是 socket path 是无法人为指定的,因为在 Linux 中就不行。Socket path 在代码中是写死的,具体的值是 /tmp/.X11-unix/X#,其中 # 是显示端口。在 Windows 中这个地址会被转换成 C:\tmp\X11-unix\X#

PulseAudio

以下是编译好的二进制:

这个没有安装包所以解压就可以用。然后你需要修改启动脚本才能使用 Unix Domain Socket。启动脚本默认的位置是 .\etc\default.pa。或者你可以把启动脚本复制到 ~\.config\pulse\default.pa 然后修改这个。在 network access 那里添加这一行(socket path 的位置可以任意修改,但必须在 NTFS 上且不能是 WSL 的路径):

load-module module-native-protocol-unix socket=C:\\tmp\\pulse\\pulse.sock auth-anonymous=1

然后你可以通过以下命令启动 PulseAudio

.\pulseaudio.exe

运行 paplay 来检验服务器是否正常运作:

.\paplay -s unix:C:\tmp\pulse\pulse.sock -p C:\Windows\media\ding.wav

如果运作正常,你会听到「叮」的一声。

设置 WSL 上的客户端

理论上说 WSL 上的软件不应该需要移植或修改。然而目前 Windows 上的 Unix Domain Socket 在 Windows 与 WSL 之间互操作的时候有一定限制:socket() 之后必须马上是 bind() 或者 connect()。其间不能有其它的 syscall。不然这个 socket 就会只能在 WSL 内部使用。所以我对 libxcblibpulse 进行了一些修改,删除了几行代码.

libxcb

按照说明安装:

然后你需要把 /tmp/.X11-unix 软连接到 C 盘实际上的 socket path:

sudo ln -s /mnt/c/tmp/.X11-unix /tmp/

检验一下是否正确:

ls -l /tmp/.X11-unix

检验一下是否可用(先启动 VcXsrv):

DISPLAY=unix:0 gnome-terminal

libpulse

按照说明安装:

检验一下是否可用(先启动 PulseAudio):

PULSE_SERVER=unix:/mnt/c/tmp/pulse/pulse.sock paplay -p /mnt/c/Windows/media/ding.wav

FAQ

Unix Domain Socket 比 TCP loopback 性能更好吗?

  • 很有可能。我用 MacBook Air 做了一个测试,用它在 2K 分辨率下全屏播放一个 YouTube 上的过山车视频,过山车画面变化很快所以 X11 很容易满载,此外也比较方便观察画面撕裂。然后我发现切换到 AF_UNIX 后 CPU 使用率下降了大约 20%。但是这个实验不够严谨,还需要更多的证据证明性能优势。

我可以在 WSL2 里用吗?

  • 目前不行。据我所知最初版本的 WSL2 不支持 AF_UNIX 互操作。当然他们也可能在正式发布之前变卦。

我不信任二进制分发

  • Cherry-pick 补丁的分支然后自己编译嘛。