远程CMD Shell中关闭StandardInput后,如何实现再次写入?
解决远程CMD Shell持续输入输出的问题
你当前的问题核心在于两个错误操作:
- 调用
process.StandardInput.Close()关闭了输入流,导致cmd.exe认为输入已结束,无法再接收新命令 - 使用
StandardOutput.ReadToEnd()同步读取输出,这个方法会阻塞直到进程退出,逼得你必须关闭输入来触发进程结束才能拿到输出
要实现持续的命令交互,正确的做法是保持输入流打开,同时用异步方式读取输出,具体方案如下:
核心修正点
- 绝不提前关闭
StandardInput,直到你确实要终止cmd进程时再关闭 - 替换同步的
ReadToEnd(),改用异步事件监听输出和错误流,避免阻塞主线程
修改后的代码示例
using System; using System.Diagnostics; using System.Text; class RemoteCmdShell { private Process _cmdProcess; private StringBuilder _outputBuilder = new StringBuilder(); public void StartCmd() { _cmdProcess = new Process(); _cmdProcess.StartInfo.FileName = "cmd.exe"; _cmdProcess.StartInfo.RedirectStandardInput = true; _cmdProcess.StartInfo.RedirectStandardOutput = true; _cmdProcess.StartInfo.RedirectStandardError = true; _cmdProcess.StartInfo.UseShellExecute = false; _cmdProcess.StartInfo.CreateNoWindow = true; // 注册异步输出/错误事件 _cmdProcess.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { lock (_outputBuilder) { _outputBuilder.AppendLine(e.Data); } } }; _cmdProcess.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { lock (_outputBuilder) { _outputBuilder.AppendLine($"[ERROR] {e.Data}"); } } }; _cmdProcess.Start(); // 启动异步读取 _cmdProcess.BeginOutputReadLine(); _cmdProcess.BeginErrorReadLine(); } // 发送命令并获取当前输出(示例逻辑,可根据需求调整) public byte[] SendCommand(string command) { if (_cmdProcess == null || _cmdProcess.HasExited) { throw new InvalidOperationException("CMD进程未启动或已退出"); } // 清空之前的输出缓存 lock (_outputBuilder) { _outputBuilder.Clear(); } // 发送命令,无需关闭输入流 _cmdProcess.StandardInput.WriteLine(command); _cmdProcess.StandardInput.Flush(); // 确保命令被立即发送 // 这里可以根据需求添加等待逻辑,比如等待特定提示符,或者短暂延迟(示例用1秒延迟,实际建议更可靠的判断) System.Threading.Thread.Sleep(1000); lock (_outputBuilder) { return Encoding.UTF8.GetBytes(_outputBuilder.ToString()); } } // 终止CMD进程 public void StopCmd() { if (_cmdProcess != null && !_cmdProcess.HasExited) { _cmdProcess.StandardInput.Close(); _cmdProcess.WaitForExit(); _cmdProcess.Dispose(); } } }
关键细节说明
- 异步事件监听:通过
OutputDataReceived和ErrorDataReceived事件,可以实时捕获cmd的输出,不需要阻塞等待进程退出 - 保持输入流打开:只要进程未退出,
StandardInput就可以持续写入新命令,写完后调用Flush()确保命令被立即发送给cmd - 输出缓存处理:用
StringBuilder加锁来线程安全地收集输出,避免多线程下的内容混乱 - 命令执行后的等待:示例中用
Thread.Sleep()做简单等待,实际场景中可以监听输出是否出现cmd提示符(比如C:\>)来判断命令执行完成,这样更准确
内容的提问来源于stack exchange,提问作者dinikai
相关产品推荐
相关产品推荐

