###### tags: `C#` # C#-SSH.net ## Install * 可以在Visual Studio的NuGet管理員裡,搜尋ssh.net並安裝 * 原始碼:[SSH.net@Github](https://github.com/sshnet/SSH.NET) * 離線安裝:[SSH.net@NuGet](https://www.nuget.org/packages/ssh.net/) 下載後,可以在Visual Studio安裝此插件 ([ssh.net.2020.0.1.nupkg](https://www.nuget.org/api/v2/package/SSH.NET/2020.0.1)) * **直接取用Renci.SshNet.dll** 若無法安裝NuGet插件,可以解壓縮.nupkg檔案,在裡面找到對應.net版本的**Renci.SshNet.dll**,將其放在bin/debug目錄即可. ```csharp using Renci.SshNet; using Renci.SshNet.Common; ``` ## API #### 僅使用帳號密碼,不使用ssh key的連線方式 ```csharp ConnectionInfo conInfo = new ConnectionInfo(_host, 22, _username, new AuthenticationMethod[] { new PasswordAuthenticationMethod(_username, _password) } ); ``` #### 連線 ```csharp SshClient sshClient = new SshClient(conInfo); ``` #### 送指令 ```csharp SshCommand sshCmd = sshClient.RunCommand("ls"); string results = sshCmd.Result; ``` ## 可能遇到的問題 ### 不能「交互」 ```sshClient.RunCommand```可以送```ls```或```uname -a```,這種類型的都沒有問題,但是像以下的情況,就會卡死。 ```python # hello.py a = input("please input a number: ") print(a) ``` 我在server寫了一個簡易的python程式做測試,當用ssh.net送出時,C#就會卡死。應該跟我用錯API有關係,我用的是以下這個 ```csharp SshCommand sshCmd = sshClient.RunCommand("python hello.py"); if (!string.IsNullOrWhiteSpace(sshCmd.Error)) { Log(sshCmd.Error); } else { Log(sshCmd.Result.Replace("\n", "\r\n")); } ``` 可能因為hello.py一直在等user輸入,所以```sshClient.RunCommand("python hello.py")```會卡死,無法跳到下一行。 ### 改用Shell #### 用CreateShell產生一個Shell,這樣就可以「交互」了 ```csharp sshClient.Connect(); Stream streamInput = new PipeStream(); Stream streamOutput = new PipeStream(); Stream streamOutputEx = new PipeStream(); Shell shell = sshClient.CreateShell(streamInput, streamOutput, streamOutputEx); shell.Start(); ``` #### 利用在 InputStream 寫資料的方式,送出指令 ```csharp StreamWriter inputStreamWriter = new StreamWriter(streamInput) { AutoFlush = true }; inputStreamWriter.Write("python hello.py" + "\n"); ``` #### 無窮迴圈讀取 OutputStream,取得輸出 ```csharp Task taskOutput = Task.Run(async () => { StreamReader streamReader = new StreamReader(streamOutput); while (sshClient.IsConnected) { if (streamOutput.CanRead) { string str = streamReader.ReadToEnd(); if (str != string.Empty) { _logEventTrigger(str); } } await Task.Delay(20); } }); ``` ### CPU使用率居高不下 爬了下文,好像是library有缺陷。```shell.Start();```這行會讓CPU使用率飆高。 >[參考資料](https://stackoverflow.com/questions/66483431/ssh-net-real-time-logging-high-cpu) [SSH.NET中有一個已知的錯誤](https://github.com/sshnet/SSH.NET/issues/702),OutputStream當沒有收到實際的新數據時,該命令會不斷地吐出空數據。 ### 解決辦法 捨棄Shell,改用ShellStream。 將inputStream與outputStart合併成一個ShellStream。 ```csharp sshClient.Connect(); shellstream = sshClient.CreateShellStream("xxx", 80, 24, 800, 600, 1024); // xxx是什麼不重要 ``` 讀取改用shellStream ```csharp Task taskOutput = Task.Run(async () => { StreamReader streamReader = new StreamReader(shellstream); while (sshClient.IsConnected) { if (shellstream.CanRead) { string str = streamReader.ReadToEnd(); if (str != string.Empty) { _logEventTrigger(str); } } await Task.Delay(20); } }); ``` 送出也改用shellStream ```csharp streamWriter = new StreamWriter(shellstream) { AutoFlush = true }; ``` ## 參考資料 * [Is it possible to execute multiple SSH commands from a single login session with SSH.NET?](https://stackoverflow.com/questions/46847304/is-it-possible-to-execute-multiple-ssh-commands-from-a-single-login-session-with) * [SSH.NET doesn't process my shell input commands](https://stackoverflow.com/questions/44528158/ssh-net-doesnt-process-my-shell-input-commands/44542531#44542531)