使用SSH.NET库无法读取SSH服务器响应的问题排查求助
排查思路与解决建议
1. 明确设备SSH服务的交互模式
很多专用设备的SSH服务并非标准POSIX shell环境,而是自定义的命令交互接口:
CreateCommand依赖标准shell的fork/exec机制执行命令,这类设备不支持该模式,会导致命令执行后无法返回(无限挂起)。- Putty连接后直接进入交互会话,说明设备SSH基于伪终端(PTY)的交互模式,而非标准命令执行通道。
2. 优化ShellStream的交互逻辑
当前ShellStream的读取逻辑存在缺陷,需匹配设备的交互格式调整:
修正命令发送的换行符
设备的Telnet/HTTP接口用VERSION?即可,但SSH交互可能仅识别特定换行符(比如部分设备只认\r而非默认的\r\n),修改发送代码:
// 替换WriteLine,直接发送带正确换行符的命令 shellStream.Write(sendStr + "\r"); shellStream.Flush();
改进读取逻辑,过滤无效字符
设备返回的\r\0属于终端控制字符,需读取完整输出并过滤:
StringBuilder responseBuilder = new StringBuilder(); DateTime startTime = DateTime.Now; // 设置超时避免无限等待 while (DateTime.Now - startTime < TimeSpan.FromSeconds(5)) { if (shellStream.DataAvailable) { string chunk = shellStream.Read(); // 过滤空字符和无效控制符 chunk = chunk.Replace("\0", "").Trim(); if (!string.IsNullOrEmpty(chunk)) { responseBuilder.Append(chunk); // 检查是否到达响应结束标记(比如设备命令响应后会回到提示符) if (responseBuilder.ToString().EndsWith(">") || responseBuilder.ToString().EndsWith("#")) { break; } } } await Task.Delay(20); } string finalResponse = responseBuilder.ToString().Trim();
3. 匹配Putty的终端交互细节
Putty连接时会发送特定的终端协商参数,需调整SSH.NET的CreateShellStream参数:
- 尝试更换终端类型(比如用
ansi替代vt100) - 关闭终端回声(避免设备回显命令导致读取到重复内容)
// 调整终端类型 shellStream = sshClient.CreateShellStream("ansi", 80, 24, 800, 600, 4096); // 发送命令关闭回声(不同设备命令可能不同,如stty -echo) shellStream.Write("stty -echo\r"); shellStream.Flush(); // 读取并丢弃回声关闭后的响应 await Task.Delay(100); if (shellStream.DataAvailable) shellStream.Read();
4. 抓包对比交互流程
用Wireshark抓取Putty和SSH.NET的SSH交互报文,重点对比:
- Putty连接后发送的终端协商参数(TERM环境变量、窗口大小、控制选项)
- 命令发送的换行符类型
- 设备响应的格式和结束标记
根据抓包结果调整SSH.NET的参数和交互逻辑。
5. 尝试直接使用SSH底层通道
如果ShellStream仍有问题,可跳过PTY模拟,直接创建SSH会话通道:
var channel = sshClient.CreateChannel<ChannelSession>(); channel.Open(); // 发送命令(带正确换行符) channel.SendData(Encoding.ASCII.GetBytes(sendStr + "\r")); // 读取响应 byte[] buffer = new byte[4096]; StringBuilder response = new StringBuilder(); while (channel.DataAvailable) { int bytesRead = channel.Receive(buffer); response.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead)); await Task.Delay(50); } channel.Close(); string result = response.ToString().Trim();
内容的提问来源于stack exchange,提问作者JimJamFlimFlam
相关产品推荐
相关产品推荐

