文章目录
- 穿越跳板机
- 配置 ProxyJump 方案
- Cygwin上的配置
- 建立 SSH Tunneling 方案
- 代码映射
- 目录映射方案
- 配置Rsync加速
- 远程服务器方案(todo)
- 远程Debug
tips:本文讲了两种穿越跳板机的方案(推荐ProxyJump方案),和两种代码映射的方案。实际任选一对搭配即可。
穿越跳板机
远程开发有时是在集群中进行,而集群中的机器位于内网环境。为了安全地访问这些内部服务器,通常会设置一个跳板机,这是在网络中的安全性边界处设置的关键访问点,用以增强整体安全性。
“穿越跳板机"就是从外部机器连接到内部服务器(以下简称"目标机"或"远程机”)的过程。
一种简单的做法是:用户先通过ssh连接到跳板机,然后再通过跳板机ssh连接到目标机。然而,这种方式在实际操作时会让人感到繁琐,因此可以通过shell工具提供的"Expect登录脚本"功能来自动化地实现,Xshell、Tabby等shell工具都有这个功能。但是我们的远程开发工具(如jetbrains IDE、vscode)并不支持,可能是它不适用于远程开发,因此要寻找更有效的解决方案。
一般所说的"穿越跳板机"指的是更加高级且无感知的方案,通过隧道技术(Tunnel)来实现,通常有两种做法:
- ProxyJump(跳板代理):这是ssh工具本身提供的功能,可以通过
ssh
命令实现,但通常在ssh配置文件(通常为~/.ssh/config
)中配置会更为方便。它通过指定一个中间服务器(跳板机),从而通过该服务器访问目标机器。
使用ProxyCommand(代理命令)也能达到相同的目的。ProxyCommand是ProxyJump的超集,能够设置更复杂/灵活的代理。但仅对于实现跳板代理来说,ProxyJump是更加简单的方式。 - 建立Tunneling(隧道转发):使用专门的隧道工具。隧道工具可以用于各种网络服务,而不仅仅是SSH。它可以用于创建安全的通信通道,如VPN、端口转发等。然而本文我们搭建的只是 SSH Tunnel,它只能用于SSH,与跳板代理在本质上有相似之处。
下面对这两种方案分别进行详细的介绍。
配置 ProxyJump 方案
跳板代理可以使用命令来指定:
- ProxyJump的命令格式是:
ssh -J <user@jump-host> <user@target-host>
- ProxyCommand设置跳板代理的命令格式是:
ssh -o "ProxyCommand=ssh -W %h:%p <user@jump-host>" <user@target-host>
但每次输入这么长的命令会很繁琐,而且JetbrainsIDE的SSH配置界面并不支持添加命令选项,因此我们采用配置文件的方式来实现。
- 用户级的配置文件:
~/.ssh/config
。 - 全局配置文件:在windows上是
%PROGRAMDATA%\ssh\ssh_config
,在macos/linux上是/etc/ssh/ssh_config
。 - 具体的配置格式参见ssh_config文件帮助手册。
一般格式:
# 使用Host关键字创建块结构
# 别名通常是一个便于记忆的名字,配置完成后可以直接通过`ssh 别名`建立连接。
Host <别名>
# 要登录的真实主机名,也就是平时我们使用ssh后面跟的地址名称,通常是ip地址。
HostName <host>
# 端口号,默认22
Port <端口号>
# 指定登录的用户名
User <用户名>
# 指定私钥文件。默认是~/.ssh/id_rsa或~/.ssh/id_dsa等文件,如果没有合适的密钥则会自动切换到密码身份验证方式。
# 在windows上,如果用的是Cygwin的ssh,则可以配置成windows用户目录,否则ssh默认是在cygwin的用户目录中找密钥文件。
IdentifyFile <私钥文件>
穿越跳板机的具体配置如下所示:
# 全局配置
Host *
# 指定 SSH 客户端接受的远程主机(服务器)提供的主机密钥算法,添加对ssh-rsa的支持。(作为客户端时才有用)
# 【为什么要配置HostKeyAlgorithms +ssh-rsa】
# openssh8.8以上的版本认为ssh-rsa加密方式不安全, 因此默认不允许这种密钥用于登陆。
# 如果使用ssh-rsa密钥会报错:Unable to negotiate with UNKNOWN port 65535: no matching host key type found. Their offer: ssh-rsa,ssh-dss.
# 这个错误表明远程 SSH 服务器提供的主机密钥类型(Host Key Type)不被你的 SSH 客户端支持。
# 具体来说,错误中提到服务器提供的两种主机密钥类型为 ssh-rsa 和 ssh-dss,而你的 SSH 客户端没有匹配的支持这两种类型的密钥。
# Q: 我用的是密码登录,和这个有关系吗?
# A: 虽然密码登录通常不涉及主机密钥验证(因为这主要用于密钥登录),但在连接时服务器仍然会提供主机密钥,
# 并且客户端会尝试验证。如果服务器的主机密钥算法不在客户端支持的列表中,就会出现这个错误。
HostKeyAlgorithms +ssh-rsa
# 指定 SSH 服务器接受的用户公钥算法。(作为服务器时才有用,放在这里是为了提醒自己)
PubkeyAcceptedKeyTypes +ssh-rsa
# 指定密钥文件
# IdentityFile <密钥文件>
# 跳板机配置
Host jump-host
HostName <跳板机ip>
User <跳板机用户名>
Port <跳板机ssh端口>
# 远程机配置
Host remote-host
HostName <远程机ip>
User <远程机用户名>
Port <远程机ssh端口>
# 指定跳板代理。多个代理可以用逗号分隔,并且将按顺序访问。
# ProxyJump jump-host
# 也可以使用ProxyCommand来配置跳板代理。ProxyJump和ProxyCommand只需要配置一个。
# 需要注意的是,JetBrainsIDE目前还不支持Windows上的ProxyJump。
# 也就是说如果使用ProxyJump,你可以通过`ssh remote-host`连接到远程机,但在JetbrainsIDE中会连接失败。
# 详见jetbrains issues:https://youtrack.jetbrains.com/issue/IDEA-214679/ProxyJump-not-supported
ProxyCommand ssh -W %h:%p jump-host
如果想要使用密钥连接,则把公钥配置到跳板机和远程机各一份即可。
配置好之后,我们可以直接执行ssh 别名
代替ssh user@ip
建立与服务器的连接。
正常来说也可以照旧用ip进行连接,但这里碰到的一个坑是:配置了ProxyJump之后,不能再通过ip访问,必须使用Host别名。当然,如果直接把Host别名配置为ip就可以了。
测试:可以通过ssh命令测试跳板代理是否成功:
> ssh <ssh配置文件中的Host别名>
# 如
> ssh remote-host
输入密码(或使用配置好的ssh密钥)即可成功连接到远程机。
Cygwin上的配置
特别说明一下Cygwin上的配置。如果用的是Cygwin的ssh,则应该编辑cygwin目录下的ssh配置文件(如用户级配置文件是cygwin64安装目录/home/<user>/.ssh/config
),而不是windows的。
由于我们可能即会用到windows自带的ssh,也可能会用到cygwin安装的ssh,因此两处的配置文件可能会写的十分相似。
一个令人愉悦的配置方式是,可以使用Include
指令来使一个配置文件包含另一个配置文件。因此我们可以这样编写cygwin上的config:
# Include 包含其它配置文件。这里包含windows用户目录的ssh配置文件,就免得在两处编写同样的配置。
Include /cygdrive/c/Users/wushu/.ssh/config
# 全局配置
Host *
# 指定的密钥文件。如果不设置,则默认是~/.ssh/id_rsa或~/.ssh/id_dsa等文件,如果没有合适的密钥则会自动切换到密码身份验证方式。
# 当前用的是Cygwin的ssh,默认会在"cygwin安装目录/home/<user>/.ssh/"中找密钥。这里指定使用windows用户目录中的密钥。
IdentityFile /cygdrive/c/Users/wushu/.ssh/id_rsa
特别注意:前面配置文件中的HostKeyAlgorithms +ssh-rsa
一定要有,或者写在这个文件里。在撰写本文时,新安装的win11自带的ssh版本是8.6,如果仅仅是这样的话不加并没有关系;但Cygwin安装的ssh版本是9.3,不加一定会报错。
建立 SSH Tunneling 方案
我们可以借助MobaXterm工具建立SSH Tunneling(SSH隧道)。
然后只需要ssh连接到本地的tunneling端口,就可以无感地将连接转发到远程机。
具体的配置如下:
-
打开MobaXterm,选择tunneling
-
创建 SSH tunnel
-
配置并保存
-
点击启动。(还可以点选自动启动和自动重连)
第一次启动时,会提示信任身份,并要求输入跳板机的ssh密码(如果没有配置密钥)。
测试:启动后,可以通过ssh命令测试隧道转发是否成功:
> ssh <远程机用户名>@<本机ip> -p <本机tunnel端口>
# 如
> ssh user@127.0.0.1 -p 12345
此命令将直接连接到远程机,如果没有配置密钥,则显示让输入user@127.0.0.1
的密码,实际上就是远程机的ssh密码。
> ssh user@127.0.0.1 -p 12345
user@127.0.0.1's password: #输入远程机的密码
Last login: Tue Dec 12 16:42:38 2023 from xxx
Welcome to tlinux 1.2 64bit
Version 1.2 20130106
代码映射
目前远程代码映射主要有两种方案:
- 目录映射(传统):用ftp/sftp、webdav等方式建立目录映射,自动或手动地同步改动的文件。
- 远程服务器(现代):jetbrains 的 gateway 和 vscode 的 remote-ssh 插件 都是这种方式。(其实严格来说这种不算是代码映射,而是远程控制)
- remote-ssh 会在远程机安装一个vscode-server,本机的remote-ssh插件和远程机的vscode-server建立连接实现远程开发。
- gateway 会在远程机安装一个对应的IDE后台程序,并在本地启动一个瘦客户端(Jetbrains Client),瘦客户端和远程机的IDE后台建立连接实现远程开发。gateway即可作为一个独立的启动器安装,也默认捆绑在jetbrains的IDE中。
两种方案的优缺点分析:
- 远程服务器方案
- 优点:是彻底的远程环境。本地运行瘦客户端可以减少本机的内存占用。
- 缺点:网络不好可能会出现卡顿,断网时无法进行编码。
- 目录映射方案
- 优点:在本地拥有代码文件,因此可以使用本地的工具来访问代码,如使用git图形化工具来管理代码,使用notepad++查看文件的空白符。
- 缺点:因为有本机和远程两份代码文件,因此可能存在比较麻烦的同步问题:大工程同步要很久,可能需要设置很多排除目录以降低同步时间。配置比较麻烦。
- 二者各有优劣,我们可以按需选择。
CLion支持这两种方案(见CLion远程开发官方文档),下面进行详细的介绍。
目录映射方案
1. 配置SSH连接。
上图示的Host和端口填写的是 ssh tunnel 方案的。如果你用的是ProxyJump方案则要填写远程机的Host(ssh配置文件中的Host别名)和端口。
2.1 配置sftp - 连接,使用刚刚配置好的ssh。“设为默认"的目的是用于在第3步"开启自动同步”(自动同步使用默认的Deployment)。Root path
通常设置为远程机上的项目根目录。
2.2 配置sftp - 目录映射。
如果刚刚把Root path
设置为远程机上的项目根目录,那么这里的"Deployment path
"可以直接写"/
"。
但如果项目很大,只想映射其中几个目录,可以通过点击Add New Mapping
添加多个映射来实现。
2.3 配置sftp - 排除目录,按需配置即可。
3. 设置自动同步策略。按需选择。始终自动同步可能会导致IDE卡顿;按下Ctrl+S
时同步是一个不错的选择。也可以不自动同步,而是完全手动上传和下载。
手动上传/下载/同步(查看差异):右击文件视图的文件或目录名,选择Deployment
,可以对该文件或目录进行上传/下载/同步。
配置Rsync加速
在配置SFTP的时候,有一个Rsync选项。使用Rsync可以显著提高同步的速度。
摘自官方文档-windows客户端细节:对于 Windows 上的文件同步,默认情况下,CLion 依靠自己的远程主机访问(Remote Host Access),并使用 tar 工具在主机端进行压缩。这种机制比 macOS 和 Linux 上使用 Rsync 工具同步的速度慢。您可以在部署设置中选择 "使用 Rsync 进行下载/上传/同步 "复选框,在 Windows 上启用 Rsync 同步。
勾选它,然后配置Rsync:
MacOS和Linux自带Rsync,所以几乎不需要再设置什么。前往Rsync的设置界面,点击
Test Connection
显示"successful"表示成功检测到工具,然后手动上传一个文件测试,一般都会成功上传。
Windows并不自带Rsync,根据CLion的提示,windows上推荐使用cygwin安装rsync和openssh,它们会被安装到cygwin的bin目录下。(首先要下载cygwin,然后用cygwin安装openssh和rsync。此文有讲解rsync的安装,用同样的方式再安装OpenSSH即可)
前往Rsync的设置界面,配置rsync和ssh的全路径,点击Test Connection
显示"successful",然后手动上传一个文件来测试,如果成功那么恭喜你。但也可能会报错Unknown message with code "Rsync failed with exit code: 12"
。
Rsync options:
--no-perms
选项用来告诉rsync
不要传输任何(文件或目录的)权限信息,否则由于windows和linux的文件权限管理方式不同,上传到linux的文件的权限会发生改变。如果远程目录也由git管理,则可以用git status、git diff <file>
清晰的看到文件权限发生了变化。
如果报错,可能是因为安装的ssh版本高于8.8。解决方法是编辑 cygwin64\home\wushu\.ssh\config
文件(如果没有则手动创建),添加以下内容:
Host *
# openssh8.8以上的版本认为ssh-rsa加密方式不安全, 因此默认不允许这种密钥用于登陆。
# 此行作用是让客户端添加对ssh-rsa的支持。
# Q: 我用的是密码登录,和这个有关系吗?
# A: 虽然密码登录通常不涉及主机密钥验证(因为这主要用于密钥登录),但在连接时服务器仍然会提供主机密钥,并且客户端会尝试验证。如果服务器的主机密钥算法不在客户端支持的列表中,就会出现这个错误。
HostKeyAlgorithms +ssh-rsa
然后再尝试上传/下载,应该就成功了。(本文在前面讲ProxyJump方案的时候,其实就已经在配置文件中添加了这条配置,目的就是应对这个问题)
如果还是失败,那么继续往下看,下面将讲解用于排查真正错误原因的方法。
——————
如何才能排查到真正的错误原因?
很多错误CLion都只会报Unknown message with code "Rsync failed with exit code: 12"
,通过这个根本无法得知具体是为何失败。因此我们需要手动测试rsync
,看到底是哪里出了问题。
进行手动测试前必须要知道的一些事情:(否则这会成为大坑)
- 我们必须保证自己使用的是用Cygwin安装的openssh和rsync。虽然windows本身也会提供一个ssh,但实际看来并不能用它,我尝试过直接在google上搜索openssh和rsync下载并安装,但实际测试始终不能成功,找不到具体的原因(心态崩)。
具体测试时出现过的情况我记录在非Cygwin安装的openssh和rsync测试情况记录。 - Cygwin是什么?
- Cygwin是一个在Windows上提供模拟Unix/Linux环境的开源软件(就像wsl)。因此它能够安装原生的linux工具,例如我们前面刚安装的openssh和rsync。
- Cygwin在windows中模拟了Linux文件系统的结构,根目录与Cygwin的安装目录映射。
- Cygwin提供一个终端工具
Cygwin64 Terminal
,在这里可以看到完整的linux目录。 - Cygwin安装的工具只依赖于Cygwin环境,这包括一些环境变量、配置文件等,而不是依赖于Windows。例如,我们安装的ssh并不会读取
C:\Users\<username>\.ssh\
中的密钥和配置,而是读取cygwin64(安装目录)\home\<username>\.ssh\
,因为cygwin64\home\<username>
才是cygwin/ssh的用户目录。即便我们不在Cygwin64 Terminal
中而是在cmd、powershell等外部终端中使用这些工具也是如此(看来是Cygwin为这些工具做了一些封装)。
- 早期版本的CLion:启用rsync后,SSH将不能使用"密码"的身份验证方式(会失败),只能使用密钥方式验证。参见相关的Issues:Download from SFTP server using rsync fails with rsync exit code 12 on Windows。目前应该已经解决了,我测试用密码方式验证身份没有问题。
我们可以直接在Cygwin64 Terminal
中测试。或者将cygwin64/bin/
配置到Windows环境变量,这样就可以用windows上的终端(如cmd、powershell)来测试。就像刚刚说的一样,无论哪种方式,ssh使用的都是Cygwin提供的环境。
配置windows环境变量时注意:一定要配置到Path变量的最前面,目的是覆盖windows提供的ssh。配置好后重新打开cmd输入
ssh -V
,如果显示OpenSSH_for_Windows_xxx
(Windows自带的ssh)则说明没有配置成功。
接下来我们尝试将一个text.cpp
同步到远程机。在当前目录下创建一个text.cpp
,然后输入以下命令:
# `v`越多日志越详细
$ rsync -avvv -e "ssh -p 12121" ./test.cpp user@127.0.0.1:~/test.cpp # 填写你的远程机用户名和地址(这里是本机tunnel的地址)
opening connection using: ssh -p 12121 -l user 127.0.0.1 rsync --server -vvvlogDtpre.iLsfxCIvu . "~/test.cpp" (11 args)
Unable to negotiate with 127.0.0.1 port 12121: no matching host key type found. Their offer: ssh-rsa,ssh-dss
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]
[sender] _exit_cleanup(code=12, file=io.c, line=231): about to call exit(12)
可以看到,导致连接失败的错误原因是no matching host key type found. Their offer: ssh-rsa,ssh-dss
。
这是由于openssh8.8以上的版本认为ssh-rsa加密方式不安全,因此默认不允许这种密钥用于登陆。通过ssh -V
看到我的openssh版本是9.3
。
有同学可能会有疑问:为什么我在CLion的
Tools -> SSH Configurations
里点击Test Connection
显示的是连接成功,这里怎么却失败了呢?
- 这是因为
SSH Configurations
里的Test Connection
使用的是在环境变量PATH中找到的ssh,默认也就是Windows带的ssh,它的版本低于8.8(我的是8.6),所以直接就能连接成功。- 而当我们启用rsync后,rsync用的是我们在
Tools -> Rsync
界面中配置的ssh,也就是Cygwin的ssh,版本是高于8.8的,因此连接失败,才出现了退出码12
的错误。- 既然这样,我们自然还会这么想:如果把rsync用的ssh配置成windows自带的ssh不就行了吗?这个问题其实还可以再进一步想:系统明明有ssh,为什么rsync还要我们配置ssh,并且建议都用Cygwin安装的。说实话我也不太清楚,CLion的官方文档中也并没有写。
我猜想的原因可能是:Cygwin安装的ssh和windows的ssh实现并不一样。尽管都是openssh,但Cygwin的ssh应该是linux上的实现,而Windows的ssh则是Windows上的实现。而cygwin安装的rsync的实现也应该是Linux上的实现。rsync的过程需要用到ssh,只有二者都是linux实现,才完全兼容,才能一起正常运行。
因此解决方法就是添加ssh -o HostKeyAlgorithms=+ssh-rsa
选项,即:
> rsync -avvv -e "ssh -p 12121 -o HostKeyAlgorithms=ssh-rsa" ./test.cpp user@127.0.0.1:~/test.cpp # 填写你的远程机用户名和地址(这里是本机tunnel的地址)
但每次都输入选项会很麻烦,并且CLion也不支持添加选项。所以最终的方法就是前面说的,编辑 cygwin64/home/<user>/.ssh/config
文件(如果没有则手动创建),添加以下内容。ssh会自动读取此配置。
Host *
# openssh8.8以上的版本认为ssh-rsa加密方式不安全, 因此默认不允许这种密钥用于登陆。
# 此行作用是让客户端添加对ssh-rsa的支持。
# Q: 我用的是密码登录,和这个有关系吗?
# A: 虽然密码登录通常不涉及主机密钥验证(因为这主要用于密钥登录),但在连接时服务器仍然会提供主机密钥,并且客户端会尝试验证。如果服务器的主机密钥算法不在客户端支持的列表中,就会出现这个错误。
HostKeyAlgorithms +ssh-rsa
然后再执行此命令,应该就可以把test.cpp
上传到远程机。如果失败,也会显示具体的错误,那么继续排查即可,只要知道具体的原因,就比较好处理了。
本节到这就可以结束了。
————
非Cygwin安装的openssh和rsync测试情况记录
记录一下测试情况,报的错都比较难排查。其中Connection reset by peer
是socket底层的错误,几乎无法排查。
我尝试理解这些错误:rsync需要和ssh配合工作,以及和远程的rsync/ssh进行通信。所以当涉及到不同平台实现的ssh和rsync配合以及通信时,出现不兼容是能够理解的。因此必须使用Cygwin安装的rsync和ssh(这应该都是基于linux实现的),才能和远程linux主机建立正确的关通信。
① 使用 Windows的openssh8.6 和 Cygwin的rsync3.2.7。这是我在手动测试时遇到的第一个问题,因为当时还不了解Cygwin,所以没有将cygwin64\bin
配置在环境变量PATH的最前面,导致ssh命令调用的是windows本机的ssh。
> rsync -avvv -e "ssh -p 12121" ./test.cpp user@127.0.0.1:~/test.cpp
opening connection using: ssh -p 12121 -l user 127.0.0.1 rsync --server -vvvlogDtpre.iLsfxCIvu . "~/test.cpp" (11 args)
rsync: connection unexpectedly closed (0 bytes received so far) [receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [receiver=3.0.6]
_exit_cleanup(code=12, file=io.c, line=600): about to call exit(12)
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]
[sender] _exit_cleanup(code=12, file=io.c, line=231): about to call exit(12)
这个错误显示了本机和远程机的rsync版本号,因此起初我误以为是版本不兼容。花了老半天时间尝试将服务器的版本更新到与本机一致。非常麻烦,结果最后因为又编译rsync还需要gcc5.x以上(而我的是gcc4.8),我无法把gcc版本升级到5.x以上(怕公司的项目不兼容),就放弃了。
也顺便记录一下rsync的安装:下载对应版本的rsync,然后进行编译安装。(见rsync安装文档)
rsync依赖很多库,因此安装过程可能会比较麻烦。比如autoconf版本低,需要python3但centos6的yum没有python3。
- centos6安装python3参考此文,但这个文章也是几年前的了,遇到问题请随机应变。安装python3后,再安装pip,然后
pip install commonmark
。- 依赖安装完毕后,再回到rsync的解压目录下执行
./configure
,应该就不报错了。然后再执行make
和make install
。
② 使用 Windows的openssh8.6 和 Google上找的rsync3.0.4;或者使用Cygwin的ssh9.3和Google上找的rsync3.0.4:
> rsync -avvv -e "ssh -p 12121" ./test.cpp user@127.0.0.1:~/test.cpp
opening connection using: ssh -p 12121 -l user 127.0.0.1 rsync --server -vvvlogDtpre.iLs . "~/test.cpp"
Unable to negotiate with 127.0.0.1 port 12121: no matching host key type found. Their offer: ssh-rsa,ssh-dss
rsync: read error: Connection reset by peer (104) # 这是socket抛出的错误
rsync error: error in rsync protocol data stream (code 12) at io.c(791) [sender=3.0.4]
_exit_cleanup(code=12, file=io.c, line=791): about to call exit(12)
③ 使用 Google上找的ssh7.3 和 Google上找的rsync3.0.4:
> rsync -avvv -e "ssh -p 12121" ./test.cpp user00@127.0.0.1:~/test.cpp
opening connection using: ssh -p 12121 -l user00 127.0.0.1 rsync --server -vvvlogDtpre.iLs . "~/test.cpp"
dup() in/out/err failed
rsync: read error: Connection reset by peer (104)
rsync error: error in rsync protocol data stream (code 12) at io.c(791) [sender=3.0.4]
_exit_cleanup(code=12, file=io.c, line=791): about to call exit(12)
远程服务器方案(todo)
因为担心网络问题还没有尝试,实际上这种方案配置起来应该比较简单。
参见CLion官方文档:使用gateway进行远程控制
远程Debug
参考CLion官方文档:远程Debug
CLion提供了两种远程Debug的方案:“远程Debug” 和 “远程GDB服务器”。此二者的区别在官方文档解释的很清楚。在做选择时,主要考虑的是如下两点:
-
"远程GDB服务器"方案要求项目必须是CMake构建的,且Debug服务器只能使用gdb-server。
什么是"debug服务器":debug工具(gdb)本身也是CS架构的,远程debug需要在远程机器上运行debug-server,再通过本机的debug-client与之连接来实现。
-
"远程Debug"方案适用于任何的构建方式,且Debug服务器可以用gdb-server,也可以用lldb-server。
由于我目前的项目并不是CMake构建的,所以这里选择选用更为通用的"远程Debug"方案。
步骤如下
① 远程机器安装gdb-server,并启动。
(暂时不清楚远程机器上的gdb-server和gdb的版本要不要保持一致或相近,如果碰到问题可以往这方面考虑。我这里安装的gdb-server凑巧和gdb的版本一样,都是7.2-50.el6
)
# 安装
yum install gdb-gdbserver
# 启动
gdbserver <监听的host>:<监听的port> <executable> # 启动gdbserver,并运行指定的可执行文件
gdbserver <监听的host>:<监听的port> --attach <PID> # 启动gdbserver,并attach到指定PID的进程
# 例。启动gdbserver,并attach到29834进程。监听1234端口,host省略表示允许来自所有host的连接。
gdbserver :1234 --attach 29834
② 先在远程机器上测试一下。 在远程机器上另开一个shell,使用gdb连接到gdbserver,看能否成功。
> gdb <executable> # 此命令启动gdb并加载符号文件
# 在gdb命令行输入此命令,连接到gdbserver
# 格式:target remote <host>:<port>
(gdb) target remote 127.0.0.1:1234
③ 本地机器创建ssh端口转发。(非必须)
由于我的远程机只开放了ssh端口,没有开放其它端口,因此不能直接连接到gdbserver监听的端口。好在ssh提供了端口转发的功能,利用ssh端口就可以间接访问到远程机器上的其它端口。(这里只介绍利用ssh命令和config配置文件进行端口转发的具体操作,用MobaXterm的同学可以自行搜索"MobaXterm如何设置端口转发"。)
方法一:通过ssh命令进行端口转发:
# 建立ssh连接并配置端口转发。将本地1234端口映射到remote-host的1234端口
ssh -L 1234:localhost:1234 <remote-user>@<remote-host> -p <ssh-port>
# 如。这里的remote-host是前面在.ssh/config中配置的远程机host别名
ssh -L 1234:localhost:1234 remote-host # 此命令执行完后,会建立ssh连接和端口转发
方法二:在~/.ssh/config
中添加端口转发的配置(如下),然后再执行:ssh remote-host
。
Host remote-host
# (前面的配置这里就不写了)
# 端口转发,本地1234端口映射到remote-host的1234端口
# 注意,ssh端口转发只有在建立连接后才生效
LocalForward 1234 localhost:1234
注意:SSH端口转发依赖于SSH连接,也就是说端口转发需要建立SSH连接后才生效,SSH连接断开后立即失效。因此在进行远程debug的过程中要保持ssh处于连接状态(可以在CLion的Terminal中建立连接,all in IDE)。
④ 测试端口转发是否生效
# (需要下载tcping工具,这个工具下载很简单,不用担心麻烦)
tcping 127.0.0.1 1234
⑤ 配置 CLion 的 Remote Debug configuration
参考官方文档:The Remote Debug configuration
-
Symbol file:"远程Debug"方案要把符号文件(symbol file)放到本地,目的是让gdb客户端加载到调试信息。通常可执行文件本身就可以很好地用作符号文件,因此直接把远程机器上编译好的可执行文件下载到本机即可(可以利用前面的映射功能同步此文件)。
低级错误提醒:编译时要使用
-g
选项才能为可执行文件加入调试信息。这个选项是我们平时调试时必须要加的。 -
Path mappings:配置本地的源码路径和远程机器的源码路径的映射。这样在debug时,程序才能在IDE设置的本地文件断点处停止。
-
Sysroot:动态库的本地根路径。根据官方文档的说法,大多数最新版本的GDB都可以自动下载文件,因此不需要指定此字段。
稍后启动debug时,在"GDB"选项卡中可以看到自动下载的过程。
也可以手动下载库文件。在GDB命令行中(在远程机器的GDB命令行或者上图的GDB选项卡)执行
info sharedlibrary
,可以看到需要哪些动态库。将这些库拷贝到Sysroot路径下,注意目录结构要保持一致:绝对路径相对于Sysroot目录,相对路径相对于本地项目路径(准确说是相对于在GDB选项卡中执行pwd
得到的路径)。
⑥ 原神(bushi) Debug !启动!😁
现在就可以像在本地运行一样检查代码。例如,像平时一样单步执行和检查变量。