通过 C# 同步应用程序中的 UI 取消 unix 调用(使用 SSH 库)的最佳方法?

发布于 2024-10-25 22:49:23 字数 417 浏览 3 评论 0 原文

我的程序(.NET 4.0)使用第 3 方 SSH 库(SSH.NET,到目前为止效果很好)发送一个基于用户在 UI 中的选择构建的 unix 命令,等待响应并输出它。当有时 UNIX 响应由于缺乏更好的术语而“挂起”时,我的问题就出现了,在这种情况下,我的程序陷入等待。在unix中,你可以转义该命令(对我来说是CTRL-C)并重试,但是在使用库时,我不确定如何提供等效的命令。

另一个问题是,发生这种情况时 UI 线程被锁定,因此即使有某种“取消”按钮,用户也无法单击它。我研究了BackgroundWorker和Threading,但这实际上没有意义,因为我的操作是同步的——程序必须等待响应,以便它可以解析它(格式、颜色等)。

任何对此的想法都会非常感激,谢谢大家!

My program (.NET 4.0) uses a 3rd party SSH library (SSH.NET, works great so far) to send a unix command that is constructed based on the user's choices in the UI, waits for the respose and outputs it. My problem arises when sometimes the unix response just "hangs" for lack of a better term, in which cases my program is stuck waiting. In unix you can just escape that command (for me CTRL-C) and try again, but when using a library, I'm not sure how to provide the equivelent.

Another problem is that the UI thread is locked when this is happening, so even if there was some sort of "Cancel" button the user wouldn't be able to click on it. I looked into BackgroundWorker and Threading, but that doesn't really make sense because my operation is synchronous - the program has to wait for the response so it can parse it (format, color, ect).

Any thoughts on this would much appriciated, thanks all!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橙幽之幻 2024-11-01 22:49:23

我无法具体谈论 SSH.NET 以及如何通过该库取消命令,但以下是我的处理方法。

我会在任务上启动“命令”,这本质上是一个单独的线程。这是我的示例代码:

private Task _commandTask;
private CancellationTokenSource _cancellation;

protected void SendCommand(object sender, EventArgs e) 
{
    if(_commandTask != null)
        return; // Can't run the task twice

    _cancellation = new CancellationTokenSource();
    _commandTask = new Task(SendSshCommand, _cancellation.Token);
    _commandTask.ContinueWith(FinishCommand, TaskScheduler.FromCurrentSynchronizationContext());

    _commandTask.Start();

    // returning control to the UI thread now
}

protected void CancelCommand(object sender, EventArgs e) 
{
    if(_commandTask == null)
        return;

    _cancellation.Cancel();
}

private static void SendSshCommand() 
{
    // Send your SSH Commands here
}

private void FinishCommand(Task task) 
{
   // Update your UI here

   // remove this task
   _commandTask = null;
   _cancellation = null;
}

因此,将从 UI 上的某个事件调用 SendCommand 方法(我假设单击按钮)。它创建一个 CancellationTokenSource 和一个新的 任务。此任务在单独的线程上调用 SendSshCommand 方法。然后,我们使用 ContinueWith 方法创建任务延续。传入 TaskScheduler.FromCurrentSyncrhonizationContext() 告诉我们要在 UI 线程而不是单独的线程上执行的延续任务。这很重要,因为如果我们不在 UI 线程上,我们就无法访问任何 UI 控件。

CancelCommand 将从取消按钮调用,它只是告诉 _commandTask 停止执行。

现在这还不是 100%,我确信您将会有需要传递给任务的状态,并且有 通用任务 结构可以帮助您完成此任务。另外,在 FinishCommand 中,您需要检查以确保任务已完成、未取消且未引发异常。阅读 .Net 4 中的任务和 TPL,您将了解如何做到这一点。

还值得注意的是,我不确定取消后您的 SSH.NET 库会发生什么情况。我认为它只会断开 SSH 会话,从而结束 Unix 机器上的进程。但同样,我不熟悉那个特定的库,所以你必须做一些测试。

希望有帮助!

I can't speak specifically to the SSH.NET and how you can cancel a command via that library, but here's how I would approach it.

I would launch the "command" on a Task, which is essentially a separate thread. Here's my sample code:

private Task _commandTask;
private CancellationTokenSource _cancellation;

protected void SendCommand(object sender, EventArgs e) 
{
    if(_commandTask != null)
        return; // Can't run the task twice

    _cancellation = new CancellationTokenSource();
    _commandTask = new Task(SendSshCommand, _cancellation.Token);
    _commandTask.ContinueWith(FinishCommand, TaskScheduler.FromCurrentSynchronizationContext());

    _commandTask.Start();

    // returning control to the UI thread now
}

protected void CancelCommand(object sender, EventArgs e) 
{
    if(_commandTask == null)
        return;

    _cancellation.Cancel();
}

private static void SendSshCommand() 
{
    // Send your SSH Commands here
}

private void FinishCommand(Task task) 
{
   // Update your UI here

   // remove this task
   _commandTask = null;
   _cancellation = null;
}

So the SendCommand method would be invoked from some event on your UI (button click I assume). It creates a CancellationTokenSource and a new Task. This task calls the SendSshCommand method on a separate thread. We then create a task continuation with the ContinueWith method. Passing in the TaskScheduler.FromCurrentSyncrhonizationContext() tells the continuation task that we want to execute on the UI's thread instead of a separate thread. This is important because if we're not on the UI thread we cannot access any of the UI controls.

The CancelCommand would be called from your cancel button, and it simply tells the _commandTask to stop executing.

Now this isn't 100%, I'm sure you're going to have state that you need to pass around to the tasks, and there are Generic Task structures to help you with that. Also, in your FinishCommand, you're going to want to check to make sure the task was completed, not cancelled, and didn't throw an exception. Read up on Tasks and the TPL in .Net 4 and you'll see how to do that.

It's also worth noting, that I'm not sure what will happen with your SSH.NET library after the cancellation. I would assume it would just disconnect the SSH session, which in turn would end the process on the Unix machine. But again, I'm not familiar with that particular library so you'll have to do some testing.

Hope that helps!

遗失的美好 2024-11-01 22:49:23

我对该库不熟悉,但如果您有一个 SSH 会话,即同一个 shell,则将该命令作为后台任务启动,并通过 Kill %1

Launch 取消它:-

命令&

取消:-

杀死%1

当然,这确实要求它位于同一个 shell 中。

如果您有一个可以工作的 shell 发送流类型接口,则 CTRL-C 是 ASCII 3。

I'm not familiar with the library but if you have one SSH session, that is, the same shell then launch the command as a background task and cancel it with a kill %1

Launch:-

command &

Cancel:-

kill %1

This does require it to be in the same shell of course.

CTRL-C is ASCII 3 if you've got a stream type interface to the shell sending that might work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文