NTE-002经验笔记CLASS · PUBLIC
排障笔记:Windows OpenSSH 的 stderr 写到几 KB 就卡死
经 ssh 在 Windows 服务器上执行命令,stdout 传十几 KB 没问题,stderr 写到约 4.6 KB 却永久阻塞。复现方法、判断依据和三种绕开方式。
- DATE
- 2026.10.01
- READ
- 1 MIN
- LENGTH
- 302 字
复现
在 Linux 上执行下面这条命令,让远端先往 stderr 写 3 KB、再写 10 KB:
bash
timeout 25 ssh my-windows-host \
'[Console]::Error.Write(("x" * 3000)); "after-3k"; [Console]::Error.Write(("y" * 10000)); "after-13k"' \
2> err.log
echo "exit=$? stderr_bytes=$(wc -c < err.log)"结果是 exit=124(超时),stdout 只有 after-3k,stderr 停在几 KB。把同样的数据写到 stdout 则两秒完成。
判断依据
| 观察 | 结论 |
|---|---|
| 所有卡住的任务,stderr 都停在 4.7~5.7 KB | 与内容无关,与字节数有关 |
| 成功的任务 stderr 都小于 2 KB | 阈值在这之间 |
| 换不复用的新连接结果相同 | 不是本机连接复用的问题 |
绕开
- 合并输出:远端命令末尾加
2>&1,PowerShell 里原生程序用*>&1。 - 写日志文件:长任务把输出重定向到文件,结束后再
Get-Content -Tail。 - 由包装进程接管:子进程的 stdout/stderr 都由包装脚本读取,统一从 stdout 回传:
powershell
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
# 逐行读取,加 O| / E| 前缀后写到自己的 stdout顺带发现
Windows 的 sshd 也不会把本机 stdin 的 EOF 转给远端进程。经 stdin 传文件时,ReadToEnd() 会一直等下去;改成逐行读取、遇到约定的结束标记就停,问题就解决了。