当从WSL1迁移到WSL2时,许多事情都会发生变化;显然,这也适用于X11转发。
我需要采取哪些步骤才能像在WSL1上一样在Windows 10上使用WSL2进行X11转发?
当从WSL1迁移到WSL2时,许多事情都会发生变化;显然,这也适用于X11转发。
我需要采取哪些步骤才能像在WSL1上一样在Windows 10上使用WSL2进行X11转发?
将以下内容添加到您的~/.bashrc
文件中:
export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1
为 Windows 上的 X11 服务器启用公共访问。
为了允许 WSL 访问 X 服务器,您需要在 Windows 防火墙中添加一个单独的入站规则,用于TCP端口6000,如 wsl-windows-toolbar-launcher 人员所描述。
正如WSL_subreddit_mod 在 Reddit 上指出的,以及您可以在Microsoft关于WSL2的文档中阅读到的,WSL2架构使用虚拟化网络组件。这意味着WSL2具有与主机不同的IP地址。这解释了为什么不能简单地将WSL1的X11转发设置传递到WSL2。
在Ubuntu关于WSL的Wiki页面下,您已经可以找到适用于WSL2的配置,位于运行图形应用程序下。以上提到的Reddit用户也建议类似的配置,并提供解决方案的另一部分:为 Windows 上的 X11 服务器启用公共访问。
这意味着将以下内容添加到您的~/.bashrc
中:
export DISPLAY=$(ip route list default | awk '{print $3}'):0
export LIBGL_ALWAYS_INDIRECT=1
在 Windows 上启用 X11 服务器的公共访问* 是启用 WSL2 的 X11 转发的最重要的部分:Windows 防火墙默认阻止通过 WSL 配置的网络接口进行连接。
需要为 TCP 端口 6000 创建单独的 入站规则,以允许 WSL 访问 X 服务器。创建规则后,根据 wsl-windows-toolbar-launcher 的说明,在新创建的规则的设置下范围中将 IP 地址范围限制为 WSL 子网:172.16.0.0/12。
*:如果您使用 VcXSrv,可以通过在 Extra Settings 中禁用访问控制来启用 X 服务器的公共访问:
或者通过调用带有 ac
标志的 vcxsrv.exe
直接启动:vcxsrv.exe -ac
,如 ameeno 在 Github 问题上指出的。
另外,这个 SO 回答 显示了如何通过 .Xauthority 文件共享密钥,从而保留完整的访问控制。
export DISPLAY = $(ip路由| awk '/ default via / {print $ 3; exit}'2> / dev / null):0
export LIBGL_ALWAYS_INDIRECT = 1
- Adam/etc/resolv.conf
文件包含多个nameserver条目,但没有一个是我的当前IP地址,这使得出现了问题。看起来有一些关于它是如何工作的假设。 - Thorbjørn Ravn Andersen-ac
)的 VcXsrv 时通过运行 xauth generate $DISPLAY .
在 WSL 中生成一个 ~/.Xauthority
文件。
然后执行 cp ~/.Xauthority /mnt/c/Users/<your login>/
,下次启动 VcXsrv 时,使用 -auth C:\Users\<your login>\.Xauthority
参数代替 -ac
。 - Arseny我想到了一个解决方案,使用Windows 10上的vxcsrv,正如其他人所指出的。它也适用于Windows 11。
https://sourceforge.net/projects/vcxsrv/
配置显示屏:
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=localhost:0
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0
resolv.conf
,请使用此定义:https://dev59.com/dVIH5IYBdhLWcg3wH5X1#63092879)然后(安装x11-apps):
sudo apt update
sudo apt install x11-apps
在wsl中:输入xcalc - 计算器应该在Windows10中打开
并且您想将设置保留在您的wsl发行版中,请将它们存储在您的~/.bashrc
中。
sudo nano ~/.bashrc
复制两行代码(从在WSL Distro中设置显示器 - 配置显示器)到末尾并保存。
现在XServer将随Windows启动而启动。
我正在使用它来进行ROS开发。对我很有效。
我的XServer不可通过互联网访问,因此可以禁用访问控制。
x11-apps
和环境变量。 - dev404本答案假设您已经有一个在Windows主机上运行的工作中的XServer和PulseAudio配置,因为您之前正在使用WSL1。(您也可能需要向命令行添加-ac参数,以便使您选择的XServer能够与WSL2一起工作。)
我采用的方法是,在我的~/.bashrc文件中添加以下内容,以确保我无论是使用静态IP地址还是DHCP在Windows主机上,甚至无论我的主机名或网络位置是否更改,都可以进行X11转发:
# Get the IP Address of the Windows 10 Host and use it in Environment.
HOST_IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r')
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=$HOST_IP:0.0
export NO_AT_BRIDGE=1
export PULSE_SERVER=tcp:$HOST_IP
按照上述步骤操作后,不管我的主机名或主机IP地址是什么,在WSL2中每次启动BASH会话时,它都将被放置在环境变量中。通过从命令行运行firefox并观看YouTube视频来测试它。你应该能够听到声音并看到应用程序本身来观看视频。此外,通过从命令行启动其他GUI应用程序进行测试。
它的作用:使用host命令从输出中获取与主机名关联的IPv4地址,从中匹配包含Windows主机IPv4地址的行的地址,除IP地址之外去掉其余信息,然后将其awk并打印到变量中,输出被修整。然后,将其用作字符串以提供必要的IP地址,用于转发X11和声音输出的环境变量。
希望如果其他方法对你不起作用(就像对我一样),这个方法能为你解决问题。
大多数CLI应用程序可以从BASH提示符或Windows终端运行。如果你想创建快捷方式,大多数CLI应用程序可以像以下示例之一设置(在这种情况下没有必要进行X11转发,除非是像Links2这样的应用程序):
C:\Windows\System32\wsl.exe -e htop
C:\Windows\System32\wsl.exe lynx
如果您想为Linux GUI应用程序创建桌面快捷方式,除非您能够在启动程序之前从您的~/.bashrc文件获取环境变量以供使用,否则您将不得不使用以下模板创建快捷方式,并在{yourprogram}位置放置程序名称:
C:\Windows\System32\wsl.exe LIBGL_ALWAYS_INDIRECT=Yes IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r') DISPLAY=$IP:0.0 PULSE_SERVER=tcp:$IP {yourprogram}
对于许多程序,您不必输入完整的命令行。 对于基于PERL或Python的程序,有时需要添加PERL和PYTHON的路径,以及程序的完整路径,在Linux使用WSL2运行此类GUI程序。对于我的一个perl程序,我必须这样做:
C:\Windows\System32\wsl.exe IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r') ; export LIBGL_ALWAYS_INDIRECT=Yes export DISPLAY=$IP:0.0 ; cd /mnt/c/Users/{yourusername}/Desktop ; /usr/bin/perl ~/wget-gui.pl
你可能需要进行一些实验才能使某些应用程序正常工作。例如,您可能需要dbus-launch一个应用程序,并需要在程序名称之前将该命令添加到快捷方式中。
C:\Windows\System32\wsl.exe LIBGL_ALWAYS_INDIRECT=Yes IP=$(host `hostname` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r') DISPLAY=$IP:0.0 PULSE_SERVER=tcp:$IP dbus-launch --exit-with-session gedit
在某些情况下,您可能需要使用一个更短的变量名。有些应用程序可能无法正常工作,但这种情况随着时间的推移正在改善。此外,请勿尝试从Windows命令提示符或PowerShell运行上述命令。它会抛出关于“grep”未被识别为内部或外部命令等错误。
以下是我在Windows 10系统上运行Linux GUI应用程序的屏幕截图,WSL2上的X11转发正常工作。
使用/etc/resolv.conf
命名服务器对我没有用,因为我在/etc/wsl.conf
中禁用了resolv.conf
生成(我有一个自定义的resolv.conf
)。
最终您希望得到WSL2主机IP地址,这也应该是您的默认路由。这是我在我的Debian WSL2发行版中的~/.bashrc
条目:
export DISPLAY=$(ip route | awk '/^default/{print $3; exit}'):0
从这个github issue中复制了我的答案。
关键是利用能够通过stdio通信的能力。
ubuntu
是安装有socat的WSL1分发的名称):mkdir -p /tmp/.X11-unix/
socat UNIX-LISTEN:/tmp/.X11-unix/X0,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d Ubuntu socat - TCP\:localhost\:6000"
基本上,这将建立一条通道,从普通的X Unix域套接字到主机的端口6000。
假设Windows上有一个运行在5555端口的TCP服务。在WSL2 Linux子系统中,后台运行以下命令(ubuntu
是安装了socat的WSL1子系统的名称):
socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntu socat - TCP\:localhost\:5555"
这只是在相反的方向上做同样的事情。您可以在WSL1分布式环境中运行以下命令:
socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntuwsl2 socat - TCP\:localhost\:5555"
在我的电脑上,它可以处理高达150MB/s的数据,虽然不是最快的,但对于大多数应用程序来说速度足够快。
export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0
export LIBGL_ALWAYS_INDIRECT=0
如果想要使用更简单的X11服务器,可以考虑 X410 和 MobaXterm。关于这些配置的详细信息,请参考 此处 和 此处。
Windows 11和Windows 10 22H2 (build 2311)及更高版本,包括WSLg。它可以轻松使用™。
"系统信息"应用程序将告诉您当前的构建版本号。
- 在管理员 PowerShell 中执行:
wsl --update
wsl --shutdown
强制重启 WSL
不要忘记删除您可能已经进行的任何其他 DISPLAY
修改。
您可以在不禁用服务器访问控制的情况下连接到X服务器。您可以在服务器上使用xauth生成cookie,然后使用Linux端上的xauth将其加载到Linux中。您可以从/etc/resolv.conf中获取服务器IP地址。以下是我的.bashrc文件内容:
k=$('/mnt/c/Program Files/VcXsrv/xauth.exe' -f 'C:\Users\xxx\Documents\scratch.xauth' -i -n -q 2>/dev/null <<EOF
generate localhost:0 . trusted timeout 604800
list
quit
EOF
)
if [ -n "$k" ]
then
export DISPLAY=$(sed '/^nameserver/ {s/^nameserver\s\s*\([0-9][0-9.]*\)[^0-9.]*$/\1/;p;};d' /etc/resolv.conf):0
xauth -q add $DISPLAY . ${k##* }
export LIBGL_ALWAYS_INDIRECT=true
fi
unset k
Cygwin/X
,我不需要生成cookie,而是使用k=$(/mnt/c/cygwin64/rootfs/bin/sh.exe -c '/bin/xauth -n list'|grep "^$DISPLAY")
来获取现有的cookie。我将export DISPLAY=...
行移到了那一行的上面。我还需要在Cygwin主目录中添加一个名为.xserverrc
的文件,其中包含exec /usr/bin/XWin -listen tcp "$@"
,以便为Cygwin X服务器启用TCP访问(在Cygwin中使用echo 'exec /usr/bin/XWin -listen tcp "$@"' >> ~/.xserverrc
)。 - T Sxinput list
获取键盘ID,然后运行xinput test <n>
查看所有键事件。 - andrewdotn我不知道这是否只适用于我的配置,但是这些解决方案在我的电脑上不起作用。它们返回地址192.168.0.254,这是我的网关而不是我的主机。
为了使其工作,我在我的Ubuntu/WSL2上使用了以下方法:
export DISPLAY="`ip -4 address | grep -A1 eth0 | grep inet | cut -d' ' -f6 | cut -d/ -f1`:0"