Powershell AcceptTcpClient()不能被Ctrl-C中断 [英] Powershell AcceptTcpClient() cannot be interrupted by Ctrl-C

查看:179
本文介绍了Powershell AcceptTcpClient()不能被Ctrl-C中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Powershell编写一个简单的TCP/IP服务器.我注意到Ctrl-C不能中断AcceptTcpClient()调用.通话后,Ctrl-C可以正常工作.我到处搜索,到目前为止,没有人报告过类似的问题.

I am writing a simple TCP/IP server using Powershell. I notice that Ctrl-C cannot interrupt the AcceptTcpClient() call. Ctrl-C works fine after the call though. I have searched around, nobody reported similar problem so far.

可以通过以下简单代码重复出现此问题.我正在使用Windows 10(最新补丁)和本机Powershell终端而不是Powershell ISE.

The problem can be repeated by the following simple code. I am using Windows 10, latest patch, with the native Powershell terminal, not Powershell ISE.

$listener=new-object System.Net.Sockets.TcpListener([system.net.ipaddress]::any, 4444)
$listener.start()
write-host "listener started at port 4444"
$tcpConnection = $listener.AcceptTcpClient()
write-host "accepted a client"

这是我运行它时发生的事情

This is what happens when I run it

ps1> .\test_ctrl_c.ps1
listener started at port 4444
(Ctrl-C doesn't work here)

推荐答案

(自PowerShell 7.0起) Ctrl-C 仅在执行 PowerShell代码时有效,而不是在 .NET方法执行期间.

(As of PowerShell 7.0) Ctrl-C only works while PowerShell code is executing, not during execution of a .NET method.

由于大多数.NET方法调用执行速度很快,因此问题通常不会浮出水面.

Since most .NET method calls execute quickly, the problem doesn't usually surface.

有关讨论和背景信息,请参见此GitHub问题.

See this GitHub issue for a discussion and background information.

关于可能的变通办法:

  • 在循环中运行,该循环定期轮询条件,在两次尝试之间休眠,并且仅在满足条件时才调用该方法,这意味着该方法将快速执行,而不是无限期地阻塞.

如果这不是一个选项(如果没有可以测试的条件),则可以后台作业 中运行阻止方法,这样它就可以在子进程中运行,调用者可以根据需要终止该子进程;请注意此方法的局限性,但是:

If this is not an option (if there is no such condition you can test for), you can run the blocking method in a background job, so that it runs in a child process that can be terminated on demand by the caller; do note the limitations of this approach, however:

  • 由于需要在隐藏的子进程中运行新的PowerShell实例,因此后台作业速度很慢且占用大量资源.

  • Background jobs are slow and resource-intensive, due to needing to run a new PowerShell instance in a hidden child process.

因为有必要跨作业处理作业的输入和输出:

Since cross-process marshaling of inputs to and outputs from the job is necessary:

  • 输入和输出将不是 live 对象.
  • 复杂的对象(除原始.NET类型的实例和一些众所周知的类型之外的对象)将是原始对象的 emulations ;本质上讲,对象具有属性值的静态副本,并且没有方法-有关背景信息,请参见此答案.
  • Inputs and output won't be live objects.
  • Complex objects (objects other than instances of primitive .NET types and a few well-known types) will be emulations of the original objects; in essence, objects with static copies of the property values, and no methods - see this answer for background information.

这是一个简单的演示:

# Start the long-running, blocking operation in a background job (child process).
$jb = Start-Job -ErrorAction Stop {
  # Simulate a long-running, blocking .NET method call.
  [Threading.Thread]::Sleep(5000)
  'Done.'
}

$completed = $false
try {

  Write-Host -ForegroundColor Yellow "Waiting for background job to finish. Press Ctrl-C to abort."

  # Note: The output collected won't be *live* objects, and with complex
  #       objects will be *emulations* of the original objects that have
  #       static copies of their property values and no methods.
  $output = Receive-Job -Wait -Job $jb

  $completed = $true

}
finally { # This block is called even when Ctrl-C has been pressed.

  if (-not $completed) { Write-Warning 'Aborting due to Ctrl-C.' }

  # Remove the background job.
  #  * If it is still running and we got here due to Ctrl-C, -Force is needed
  #    to forcefully terminate it.
  #  * Otherwise, normal job cleanup is performed.
  Remove-Job -Force $jb

  # If we got here due to Ctrl-C, execution stops here.
}

# Getting here means: Ctrl-C was *not* pressed.

# Show the output received from the job.
Write-Host -ForegroundColor Yellow "Job output received:"
$output

  • 如果执行上述脚本,并且不按Ctrl-C键,则将看到:
    • 如果您按Ctrl-C,则会看到:
    • If you do press Ctrl-C, you'll see:

    这篇关于Powershell AcceptTcpClient()不能被Ctrl-C中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆