关于您的特定 SSH 用例,仍然可以自然地取消挂起的 SSH 请求,具体取决于您用于发出 SSH 命令的方法。例如,SSH.NET 库提供SshCommand.BeginExecute
//方法EndExecute
,CancelAsync
称为异步编程模型 (APM) 模式。像这样的 APM 可以很容易地包装为 await-able 和 cancel-ableTask
,使用TaskCompletionSource
and CancellationTokenSource
。
例如,使用 SSH.NET 执行异步 SSH 命令可能如下所示:
Imports System.Threading
Imports System.Threading.Tasks
Imports Renci.SshNet
Module Module1
Async Function ExecSshCommandAsync(command As Renci.SshNet.SshCommand, ct As CancellationToken) As Task(Of String)
Dim tcs As TaskCompletionSource(Of String) = New TaskCompletionSource(Of String)
Dim doCancel As Action = Sub()
command.CancelAsync()
tcs.TrySetCanceled()
End Sub
Using ct.Register(doCancel)
Dim asyncCallback As System.AsyncCallback = Sub(iar As IAsyncResult) tcs.TrySetResult(command.EndExecute(iar))
command.BeginExecute(asyncCallback)
Await tcs.Task
End Using
Return tcs.Task.Result
End Function
Sub Main()
Dim command As Renci.SshNet.SshCommand
' Initialze the SSH session etc
' signal cancellation in 10 sec
Dim cts As CancellationTokenSource = New CancellationTokenSource(10000)
' Blocking wait for result with 10 sec timeout
Dim Result = ExecSshCommandAsync(command, cts.Token).Result
Console.WriteLine(Result)
' If Main was async too, we could await ExecSshCommandAsync here:
' Dim result = Await ExecSshCommandAsync(command, cts.Token)
End Sub
End Module
如果您使用单独的控制台进程(如 Putty)执行 SSH 命令,您仍然可以使用几乎相同的技术。它将异步读取和解析子进程的控制台输出,并注册一个取消例程,该例程将终止该进程Process.Kill
(或者做一些更好的事情,比如GenerateConsoleCtrlEvent
终止它,更多信息)。
此外,如果您只对子 SSH 进程的退出代码感兴趣,还有另一种方法。你可以变成Process.Handle
一个可等待的任务,结果你可以用类似的方式等待。取消回调(通过 注册CancellationToken.Register
)将终止进程,并使任务取消。或者该过程可以自然完成。在这两种情况下,任务都将达到已完成状态,并且异步等待将结束。
请记住,TaskCompletionSource.TrySetCanceled
如果您await
使用TaskCompletionSource.Task
.