Powershell AcceptTcpClient()不能被Ctrl-C中断 [英] Powershell AcceptTcpClient() cannot be interrupted by 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屋!