TIM-1EARCHIVE TERMINAL // 2026

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 字
CONTENTS · 目录(4)
  1. 复现
  2. 判断依据
  3. 绕开
  4. 顺带发现

复现

在 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阈值在这之间
换不复用的新连接结果相同不是本机连接复用的问题

绕开

  1. 合并输出:远端命令末尾加 2>&1,PowerShell 里原生程序用 *>&1。
  2. 写日志文件:长任务把输出重定向到文件,结束后再 Get-Content -Tail。
  3. 由包装进程接管:子进程的 stdout/stderr 都由包装脚本读取,统一从 stdout 回传:
powershell
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError  = $true
# 逐行读取,加 O| / E| 前缀后写到自己的 stdout

顺带发现

Windows 的 sshd 也不会把本机 stdin 的 EOF 转给远端进程。经 stdin 传文件时,ReadToEnd() 会一直等下去;改成逐行读取、遇到约定的结束标记就停,问题就解决了。