VS Code远程连接服务器:Remote-SSH安装、SSH免密与故障排查
本地机器只有 8G 内存、硬盘还剩不到 20G,可要跑的代码偏偏得放在那台 32 核的远程服务器上——这个矛盾几乎每个做后端、做算法、做数据处理的人都遇到过。解法其实很成熟:本地装 VS Code 当"操作台",真正的代码、编译、运行、调试全丢给远程服务器。这套组合听起来就是装个软件、连个 IP,但我在帮人排查问题的过程中发现,卡住的人九成不是卡在"装 VS Code"这一步,而是卡在 SSH 免密、远端 server 下载、权限和端口转发这几层看不见的地方。这篇文章就把 VS Code 安装和远程服务器连接这两件事拆开讲透:安装时那些容易被一路"下一步"忽略的选项到底影响什么,SSH 那一层怎么打牢,Remote 插件在远端到底装了什么、为什么升级客户端之后会突然连不上,以及没外网、家目录不可写、/tmp 挂载受限这些真实环境里怎么绕过去。不管你是第一次配,还是配过但总出玄学问题,下面的内容都能直接对着抄。
1. 本地编辑器跑远端代码:这套组合到底在解决什么问题
1.1 三种常见做法各自的天花板
在讲安装之前,得先把方案选清楚,因为很多人一开始就选错了路,后面所有折腾都是在给错误方案打补丁。常见的做法有三种:一是在本地开发,写完用 scp 或 git 推到服务器再跑;二是直接在服务器上用 vim 或 nano 改代码;三是本地编辑器 + 远程开发插件,代码存在远端,编辑体验在本地。
第一种做法的问题在于"反馈环"太长。你改一行代码,传到远端,跑一遍,报错了,再回来改,中间还要处理路径、依赖、环境变量不一致的问题。本地能跑的代码到远端跑不起来,这种撕裂感会消耗掉大量时间。第二种做法的问题是编辑效率,vim 配得再好,代码跳转、多文件重构、图形化 diff 这些体验还是比不上现代编辑器,而且终端一断,什么都没了。
第三种做法把两边的优势拼起来了:文件系统在远端,所以不存在"同步"这个概念,改完保存就是改完了;UI 在本地,所以享受本地显卡、字体、快捷键的完整编辑体验。这个方案的技术底座就是 VS Code 的 Remote 系列插件,其中最常用的是 Remote - SSH。我个人的判断标准很简单:只要你的代码最终要在另一台机器上跑,就应该用远程开发模式,而不是本地写完再传。
1.2 哪些场景其实不需要远程开发
反过来说,也有不少人用错了地方。如果你的项目就是一个纯前端小应用,本地 node 跑得好好的,为了"看起来专业"去配一套远程开发,纯属给自己找麻烦——每一次保存都要走网络往返,文件搜索、全局替换的响应速度会明显变慢,尤其是项目里 node_modules 特别大的时候。
另一个容易踩的误区是把远程开发当成"隔离环境"用。有人想着在远端服务器上随便折腾,反正本地不受影响。但实际用下来,远端环境一旦被搞坏,恢复成本比本地高得多,因为你对那台机器的掌控力更弱,出问题时你可能连个图形界面都没有。真要隔离,容器方案更合适,而这个话题我们在第 7 节还会再碰一次。
1.3 这套方案对两端的真实要求
我列一下自己配环境时的检查清单,这些东西在安装之前就该确认,而不是装完了才发现不行:
| 检查项 | 本地 | 远端 |
|---|---|---|
| 系统版本 | 近几年的主流桌面系统均可 | 内核 3.10 以上,glibc 建议 2.28 以上 |
| 网络 | 能访问远端 SSH 端口 | 首次连接需要能下载 server 组件 |
| 磁盘 | 客户端 + 扩展约 1G | 家目录至少留 2G 给 server 和扩展 |
| 权限 | 普通用户即可 | 家目录可写,不能是只读挂载 |
| 端口 | 无需额外开放 | SSH 端口放行,其余端口靠隧道转发 |
这张表里最容易被忽略的是"glibc 版本"和"家目录可写"。前者决定了新版客户端能不能在远端跑起来 server,后者决定了一堆莫名其妙的 Permission denied 是怎么来的。这两个坑我后面都会单独展开。
2. 装 VS Code 这一步,选项比想象中重要
2.1 Windows 上用户级安装与系统级安装的取舍
Windows 安装包会给你两个选择:用户安装和系统安装。界面上只是一个小字说明,很多人随手选了默认。区别在哪里?用户安装会把程序装到当前用户的本地应用目录下,整个安装过程不需要管理员权限,升级时也不需要提权;系统安装装到公共程序目录,所有账户都能用,但每次升级都要过一遍权限确认。
如果你的电脑是公司统一管理的,没有管理员权限,那只能选用户安装,这没什么可纠结的。但如果两种都能选,我建议选用户安装,理由很实际:升级不需要打扰 IT 部门,插件和配置都跟着你自己的账户走,出问题卸载干净不留尾巴。系统安装的唯一优势是多账户共用,这个场景在个人开发机上基本不存在。
安装向导里还有一组复选框,值得逐个看一眼。"添加到 PATH"必须勾上,它决定了你能不能在终端里敲code .直接打开当前目录——这个命令一旦用顺了就回不去了,后面讲远程连接调试时也会反复用到。"注册为文件类型编辑器"看个人习惯,如果你不想让 .txt、.log 之类的文件默认被 VS Code 抢走,就别勾。"添加右键菜单"建议勾,不是为了右键打开文件,而是为了右键打开文件夹——在项目根目录上右键直接进编辑器,比先开编辑器再找目录顺手得多。
2.2 macOS 与 Linux 上的安装方式差异
macOS 上安装就是把应用拖进"应用程序"目录,真正需要注意的是命令行工具。装完之后打开命令面板,执行Shell Command: Install 'code' command in PATH,它会往你的 shell 配置里塞一个软链接,之后终端里code就能用了。这一步不做,你在终端里敲code会提示找不到命令,很多人以为是没装好。
Linux 上的选择更多,但坑也更多。包管理器安装最省事,不过有一条经验值得强调:尽量用官方提供的安装包格式,避免用沙箱化的包分发方式。原因在于远程开发插件需要在本地起一些辅助进程、访问一些路径,沙箱化的打包方式会限制这些操作,表现出来就是连接能建立但各种小功能异常,而且报错信息很不直观,你会怀疑是远端的问题,其实问题在本地。
如果你连安装权限都没有,还有个方案:下载压缩包版,解压到任意可写目录直接用。这种版本默认把配置和插件存在用户目录里,如果想做成"绿色版",可以在解压目录里手工建一个data文件夹,它会优先使用这个目录存配置,方便你把整个开发环境拷到 U 盘或者别的机器上。
2.3 装完先做的三件小事
第一件,验证命令行。开一个终端敲code --version,能打印出版本号和 commit id 就说明 PATH 通了。这个 commit id 后面会非常关键,它是本地客户端和远端 server 之间对暗号的凭据,务必记一下位置怎么查。
第二件,打开设置同步。如果你有多台机器,把设置、快捷键、插件列表同步起来,换机器的时候不用从零配。但这里有个细节:插件列表同步和远程插件是两回事,同步的一般是本地插件,远端那一套是独立管理的,后面第 7 节会详细说。
第三件,改一个基础设置省点事。在设置里搜files.autoSave,改成onFocusChange,也就是焦点离开编辑器时自动保存。远程开发模式下,文件走网络写入,手动保存频繁触发会让体感变卡,改成离开焦点保存,体感会顺很多。
3. SSH 那一层没打牢,后面全是玄学问题
3.1 先用命令行把连接跑通,再碰插件
这是我给所有人的第一条建议:不要在 VS Code 里调试 SSH。插件的报错信息是二手的,它会吞掉一部分原生命令的输出,你看到的"连接失败"背后可能是十种不同的原因。正确的顺序是先在终端里把ssh user@host跑通,能正常登录、能执行命令,再去 VS Code 里点连接。
跑通的标准有两条:一是不需要输入密码,二是不需要输入二次验证之外的任何交互。第一条是重点,因为 Remote 插件在后台建立连接时是非交互的,如果你的密钥没配好、只能靠密码登录,插件会反复弹密码框,或者直接连接超时,而你在命令行里手动输密码是感觉不到这个问题的。
3.2 密钥生成与 config 文件的正确写法
生成密钥用一条命令就够:
ssh-keygen -t ed25519 -C "workstation-2024"选 ed25519 而不是默认的 RSA,原因有两个:密钥更短、签名更快,而且现代服务端基本都支持。-C后面的注释是给你自己看的,写在公钥尾部,机器多了之后能靠它区分是哪台机器的密钥,建议写清楚。
生成后把公钥内容追加到远端的~/.ssh/authorized_keys。如果远端支持ssh-copy-id,一条命令解决;不支持就手动做:
mkdir -p ~/.ssh && chmod 700 ~/.ssh cat >> ~/.ssh/authorized_keys # 粘贴公钥内容,Ctrl+D 结束 chmod 600 ~/.ssh/authorized_keys注意这里的权限设置不是可选项。SSH 对权限极其敏感,如果authorized_keys是 644 或者家目录是 777,服务端会直接忽略这个文件,然后回退到密码认证。你看到的现象就是"密钥明明放对了,还是要输密码"。
然后是配置文件~/.ssh/config,这个东西的价值在于把一长串连接参数固化成一个别名:
Host dev-box HostName 10.0.0.21 User worker Port 2222 IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 30 ServerAliveCountMax 6 TCPKeepAlive yes ControlMaster auto ControlPath ~/.ssh/cm-%r@%h:%p ControlPersist 10mServerAliveInterval和ServerAliveCountMax这两行是保命的,意思是每 30 秒发一个心跳包,连续 6 次没有回应才判定断开。没有这两行,中间只要有一层网络设备做空闲连接清理,你坐在那儿看代码什么都没干,过几分钟连接就断了,终端里显示Connection closed by remote host,然后你重新连、重新 cd 到目录、重新激活环境,一天下来光这个动作能耗掉半小时。
ControlMaster那三行是连接复用,第一次连接建立之后,后续同一目标的连接直接复用这条链路,不用重新握手。在 Remote 插件场景下这个收益很明显,因为插件可能会同时开好几条连接(一条控制通道、一条转发通道),没有复用时握手开销会叠加。
3.3 免密登录失败时按这个顺序查
如果你按上面配完还是要输密码,按这个顺序查,基本能定位到:
- 在远端执行
ssh -v 本机地址反连一下,或者直接看服务端日志里的认证过程,能明确看到是"密钥被拒绝"还是"根本没有尝试密钥"。 - 检查家目录权限,必须是 755 或更严格,不能是 777。家目录太宽松,服务端会认为别人可以篡改你的
authorized_keys,直接拒绝使用。 - 检查
.ssh目录是 700、authorized_keys是 600。 - 检查
authorized_keys文件的属主是不是你。用管理员账户帮忙创建过文件,属主变成别人,同样会被忽略。 - 检查是否启用了强制访问控制机制,某些系统上即使文件权限正确,安全上下文不对也会导致读取失败,需要手动恢复一下上下文。
这五步之外还有一种情况:你连的账户被限制只能用密码登录,或者被限制了来源地址。这种一般要看服务端的认证配置,最好先问清楚管理员,别自己瞎改。
4. Remote-SSH 的真实架构:UI 在本地,干活的是远端那个 server
4.1 第一次连接时到底发生了什么
理解这个流程能省掉你后面 80% 的困惑。你点下"连接到主机"之后,发生的事情大致是:
本地插件先用你配置的 SSH 参数建立连接,同时在本地起一个很小的服务端组件;连上之后,它检查远端是否存在匹配当前客户端 commit id 的 server 组件,如果不存在或者版本对不上,就从远端下载并解压到用户目录下的隐藏文件夹里;然后启动这个远端 server,让它监听一个随机端口;最后在本地和远端之间建立端口转发,本地 UI 通过这条隧道和远端 server 通信。
关键点在于:你的文件操作、终端命令、语言服务、调试器,全部跑在远端。本地只负责渲染界面。所以你看到的"打开文件夹很慢"其实是远端文件系统的速度,"跳转定义失效"其实是远端的语言服务没起来,"终端里命令找不到"其实是远端的环境变量没配好。搞清楚这个分工,很多问题就有的放矢了。
4.2 那个隐藏目录里装了什么,为什么不能随便删
远端用户目录下会有一个隐藏文件夹,里面按 commit id 分目录存着不同版本的 server,还有你安装在远端的插件、日志文件。这个目录占用的空间不小,几百兆到几个 G 都正常。
能不能删?能删,但要知道后果:删了之后下次连接会重新下载一遍,如果你在没外网的环境里,那就直接连不上了。所以我在磁盘吃紧的时候,做法是只删旧版本的子目录,保留当前客户端对应的那个。查看当前版本的方法是本地菜单里的"关于",把 commit id 记下来,远端目录里对得上的那个就是正在用的。
另一个常见现象是:你升级了本地客户端,第二天连远端就失败了。原因就是 commit id 变了,远端找不到对应版本,想下载新的又因为没外网而失败。这个坑的解法在第 6 节讲。
4.3 什么时候该用容器,什么时候老老实实用 SSH
Remote 系列除了 SSH,还有容器方案。容器方案的价值在于环境一致性:把整个开发环境定义成一个配置文件,谁都能复现。但它要求远端装了容器运行时,还要处理用户映射、卷挂载、网络模式这些事,学习曲线比 SSH 陡不少。
我的判断标准是这样的:如果是团队协作,项目依赖复杂,每个人都配环境配得死去活来,那就上容器方案;如果是自己一个人用一台固定的机器,环境已经配好了,那用 SSH 直连最省事。最忌讳的是"为了用容器而用容器",折腾两天装好容器运行时,结果发现挂载目录的权限映射没搞对,代码都写不进去。
5. 第一次连接失败的排查链路:从日志到进程逐个看
5.1 先看插件自己打出的完整命令行
连接失败时,第一个动作不是猜,而是把插件的日志打开。命令面板里搜 Remote 相关的日志命令,会弹出一个输出面板,里面记录了插件执行的完整 SSH 命令行,包括所有参数。把这一行复制出来,在本地终端里原样执行,加上-v参数看详细过程。
这一步的价值在于把"插件的黑盒"变成"你能看懂的命令"。很多时候插件失败的原因是参数组合问题,比如它默认启用了某种认证方式,而你的环境不支持,原样跑一遍立刻就能看出来。
顺便说一句,日志里会显示它到底在等什么。如果是卡在"正在下载 server"这一步超过一分多钟,那基本可以判定是远端到下载源的网络问题,不是 SSH 连接问题,两者的排查方向完全不同。
5.2 磁盘空间、临时目录与执行权限这三件事
远端 server 下载下来要解压,解压需要空间,而且它会在临时目录里做中转。这里有几个非常隐蔽的坑:
临时目录被挂载成不可执行。有些环境的临时目录出于安全考虑禁用了执行权限,表现是文件都在,但启动 server 时报权限错误。这种情况要改插件设置,让它别用默认临时目录,或者换个安装路径。
磁盘配额限制。你的家目录看起来有几个 T,但实际有配额,写几百兆就被拒绝。server 下载到一半失败,报错含糊。查配额用quota -s或者问管理员。
目录被别的账户创建过。如果你曾经用管理员账户连过一次,server 目录的属主就变成管理员了,之后你用普通账户连,写不进去。表现是一直提示权限拒绝。解法是让有权限的人把目录改回你的属主,或者你换个安装路径。
5.3 系统库版本不满足导致 server 起不来
这是我遇到最多、也是最容易被误判的一类问题。较老的服务端系统上,系统库版本偏低,新版客户端附带的运行时会直接拒绝启动,报的错大概是"需要更高版本的系统库"。这个错误在日志里能看到,但很多人看到一堆报错就放弃了。
两条路:一是升级系统库,风险是所有依赖它的程序都会受影响,生产环境慎用;二是降低本地客户端版本,退到与该系统兼容的版本。第二条路更稳,我现在还保留了一个旧版本的客户端专门用来连老机器,装成便携版放那儿,需要的时候打开。
如果你的目标机器确实是长期不升级的,我建议尽早做这个决定,别指望官方后续版本会降低门槛,方向只会越来越新。
6. 远端没有外网时,怎么把 server 手动塞进去
6.1 让本地下载、自动上传
插件本身提供了一个设置项,可以控制 server 组件的下载位置。默认策略是远端能下就远端下,下不了再本地下。如果你的远端完全没有对外访问能力,把它改成"始终在本地下载",插件会在本地下好再通过 SSH 通道传过去。
这个设置的好处是全自动,你什么都不用管;缺点是本地也需要能访问下载源。如果本地也不方便,那就走下面这步手工搬运。
6.2 手工搬运的完整步骤
第一步,确定目标 commit id。本地客户端菜单里的"关于"里有,格式是一串十六进制字符。
第二步,在能上网的机器上下载对应平台的 server 压缩包。下载地址的规律是固定的:域名后面拼上 commit 路径、平台标识和发行通道。平台标识要选对:远端如果是 x86_64 的 Linux,选 x64;如果是 ARM 架构,选 arm64。选错的表现是解压后运行时报"格式错误"。
第三步,把压缩包传到远端。用 scp 或者你手上任何能用的传输方式,落到家目录下临时位置即可。
第四步,解压到正确位置。目标路径是隐藏目录下的版本子目录:
mkdir -p ~/.vscode-server/bin/<COMMIT_ID> tar -xzf vscode-server-linux-x64.tar.gz -C ~/.vscode-server/bin/<COMMIT_ID> --strip-components=1注意--strip-components=1这个参数,压缩包里带一层顶层目录,不剥掉的话文件会多套一层,插件找不到入口文件,会一直提示下载失败。剥掉之后,确认入口脚本存在且可执行:
ls -l ~/.vscode-server/bin/<COMMIT_ID>/bin/ chmod +x ~/.vscode-server/bin/<COMMIT_ID>/bin/*第五步,重新连接。插件检测到目录存在且版本匹配,就不会再尝试下载。
6.3 多台机器批量部署的做法
手里有十几台机器的时候,一台台搬很痛苦。我的做法是先在本地把整个版本目录准备好,打成压缩包,然后写一个小脚本循环推送:
for h in box01 box02 box03; do ssh "$h" "mkdir -p ~/.vscode-server/bin/<COMMIT_ID>" scp ./server.tar.gz "$h":/tmp/server.tar.gz ssh "$h" "tar -xzf /tmp/server.tar.gz -C ~/.vscode-server/bin/<COMMIT_ID> --strip-components=1 && chmod +x ~/.vscode-server/bin/<COMMIT_ID>/bin/*" done前提是各台的架构一致。混着 x86 和 ARM 的集群要先把机器分组,别指望一个包通吃。
还有个更省事的思路:如果这些机器互相之间能通,可以在其中一台上装好,然后从这一台向其他台分发。省掉本地到每一台的流量,速度快很多。
7. 端口转发、远程调试与扩展安装位置的选择
7.1 自动转发怎么工作,什么时候会打架
你在远端的终端里起一个服务,监听某个端口,插件会自动检测到并在本地做一次端口转发,然后你在本地浏览器里访问就能看到页面。这个功能省掉了手动敲隧道命令的麻烦,但有两个地方容易出问题。
检测来源。有的插件通过扫描进程列表来发现监听端口,有的通过解析终端输出来发现。扫描进程的方式覆盖面广但延迟大,解析输出的方式反应快但容易漏。如果你起了服务但本地访问不了,先检查插件设置里这个来源配置,换另一个试试,往往就出来了。
端口占用。远端 8000 端口被占了,本地 8000 恰好也被占了,转发就会失败,或者被分到另一个本地端口。我的习惯是把本地常用端口段避开,远端用什么随意,反正转发过去本地会自动换。
7.2 远程调试的关键是"调试器也跑在远端"
这是新手最常误解的一点。在远程模式下,调试器的启动、断点命中、变量求值都在远端进行,本地只显示结果。这意味着:
- 你要调试的运行环境,必须装在远端,不是本地;
- 调试配置文件里的路径,是远端路径,不是本地路径;
- 如果调试配置里写了
cwd、program这类字段,都要用远端视角写。
我见过有人把本地的虚拟环境路径写进配置,然后奇怪为什么断点不生效。断点显示"未绑定",通常就是这个原因——本地调试器根本没有加载那份代码。
7.3 扩展到底装在哪一端
这是一个需要建立清晰心智模型的地方。扩展分两类:一类需要在远端运行,比如语言服务、调试器、代码检查工具,它们要读取远端的文件、调用远端的解释器,必须装在远端;另一类是纯界面扩展,比如主题、图标包、快捷键映射,装在本地就够了。
怎么判断?最省事的办法是:在远程窗口里装扩展,让它自己决定。插件市场会标记该扩展是否支持远程,装的时候看那个标记,标了"工作区"的会装到远端,标了"界面"的装本地。装错的典型症状是:扩展在本地列表里明明有,但远程窗口里不生效,或者反过来。
顺带说一句,远端插件装多了会明显拖慢连接速度,因为每次连接都要检查一遍插件目录。我定期清理远端插件,只留当前项目真的用得上的那几个,连接速度肉眼可见地变快。
8. 长时间使用后才会暴露的几个坑
8.1 文件监视上限与大仓库的卡顿
项目文件一多,你会发现保存一次要卡几秒,编辑器右下角转圈。多数情况下这不是网络问题,是远端的文件监视资源不够用。系统对单个用户能监视的文件数量有上限,默认值往往只有几万,大仓库轻松突破。
查当前值和上限:
cat /proc/sys/fs/inotify/max_user_watches调整需要管理员权限,而且要注意这是全用户生效的。改完之后,插件还要重启一次才认。同时,在项目设置里把明显不需要监视的目录排除掉:
{ "files.watcherExclude": { "**/node_modules/**": true, "**/dist/**": true, "**/.git/objects/**": true }, "search.exclude": { "**/node_modules": true, "**/build": true } }这两个配置是远程开发里投入产出比最高的调优项,改完体感提升非常明显。
8.2 家目录不可写与小容量 home 的绕行方案
有些机器的家目录挂载在共享存储上,容量很小;还有些机器的家目录干脆不允许普通用户写入。这两种情况,server 组件装不进去,连接必然失败。
插件的设置里可以指定 server 的安装路径。把它指到一个你有写权限、空间够用的目录,比如挂载的大盘下面的个人目录,问题就解决了。改完之后建议清一下旧的隐藏目录,避免两套组件互相干扰。
还有一个细节:如果你换了安装路径,远端插件目录也跟着换个位置,但插件配置里可能还残留着旧路径的引用,表现是插件装上了但不生效。遇到这种,直接清掉重装最快。
8.3 断线之后的状态恢复
网络不稳的环境里,连接断开是常态。断开之后有几个体验上的坑值得提前知道:
终端会丢失当前的前台进程。如果断的时候你正在跑一个长任务,SSH 连接一断,进程很可能收到信号直接退出。正确做法是用会话保持工具把任务挂在后台,或者用nohup之类的机制,别指望终端保活。
未保存的编辑器缓冲会保留,重连后还能恢复,这个做得不错。但如果你断线时间太长,远端 server 被系统回收了,重连时会重新启动一个实例,这时候打开的文件会重新从磁盘读,未保存的改动就丢了。我的习惯是重要改动随手保存,别指着编辑器的恢复功能。
调试会话一定会断。断线后重连,调试器需要重新 attach 或者重启,这一点要有心理准备,长流程的调试尽量在稳定网络下进行。
8.4 一点个人体会
配环境这件事,最大的成本从来不是操作本身,而是"不知道自己在等什么"。你点下连接按钮,中间发生了握手、认证、查版本、下载、解压、启动、转发这么多步,任何一步卡住,对外表现都是同一个"正在连接中"。我现在的做法是:第一次连一台新机器,一定先在命令行把 SSH 跑通并且确认免密可用,然后打开插件的日志输出面板盯着连接全过程,把每一步耗了多久记下来。第一次多花十分钟,后面所有问题都有参照——同样是卡住,卡在认证阶段和卡在下载阶段,排查方向完全是两回事。
另外那个"未完待续"其实挺真实的,远程开发这一套东西永远有得可挖。我自己后面还想补的两块:一是怎么把这套环境做成可复现的配置,换机器时十分钟内恢复;二是多台机器之间快速切换的工作流,比如同时连三台不同角色的机器,怎么管理窗口和终端不混乱。这两块等实际用出稳定套路了再整理。
最后再分享一个我觉得特别省事的小技巧:把你所有常用机器的连接信息都写在同一个 config 文件里,用统一的命名前缀,比如都叫 work- 开头。这样在 VS Code 的连接列表里它们会聚在一起,而且你在任何终端里敲ssh work-然后按 Tab,就能列出所有候选,不用记 IP 也不用翻笔记。这个习惯我从配第二台机器开始坚持到现在,实实在在地省下了每次找地址的时间。