Выход из процедуры прослушивания UDP - PullRequest
0 голосов
/ 24 ноября 2018

Я пытаюсь написать подпрограмму в powershell, которая будет прослушивать порт UDP, а затем выходить при нажатии клавиши.У меня проблема в том, что программа будет выходить только после того, как датаграмма будет прочитана.

Т.е. будет считано n значений, пользователь нажмет F12, программа будет ждать, пока не получит n + 1-е значение, затем выйдет,

Что должно произойти: читает n значений, пользователь нажимает F12, программа должна закрыться.

$endpoint = New-Object System.Net.IPEndPoint ([IPAddress]::Any, $port)
$continue = $true
while($continue)
{

    if ([console]::KeyAvailable)
    {
        echo "Exit with F12";
        $x = [System.Console]::ReadKey() 

        switch ( $x.key)
        {
            F12 { $continue = $false }
        }
    } 
    else
    {

        $socket = New-Object System.Net.Sockets.UdpClient $port
        $content = $socket.Receive([ref]$endpoint)
        $socket.Close()
    [Text.Encoding]::ASCII.GetString($content)
    }    
}

Я совершенно новичок в Powershell, поэтому, возможно, это невозможно.Остальная часть кода была украдена из других ответов здесь.

1 Ответ

0 голосов
/ 25 ноября 2018

Решение, использующее свойство ReceiveTimeout, которое упоминается в комментарии @ bluuf:

$p = 17042
$e = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Any, $p)
$u = New-Object System.Net.Sockets.UdpClient $p
$u.Client.ReceiveTimeout = 100
try
{
  for()
  {
    try
    {
      $b = $u.Receive([ref]$e)
      $s = [System.Text.Encoding]::ASCII.GetString($b)
      Write-Host $s
    }
    catch [System.Net.Sockets.SocketException]
    {
      if ( $_.Exception.SocketErrorCode -ne 'TimedOut' )
      {
        throw
      }
    }
    if ( [System.Console]::KeyAvailable )
    {
      $x = [System.Console]::ReadKey($true)
      if ( $x.key -eq [System.ConsoleKey]::F12 )
      {
        Write-Host 'Exit with F12'
        break
      }
    }
  }
}
finally
{
  $u.Close()
}

Асинхронная версия может выглядеть следующим образом:

if( -not('CallbackEventBridge' -as [type]) )
{
  Add-Type @'
    using System;

    public sealed class CallbackEventBridge
    {
      public event AsyncCallback CallbackComplete = delegate { };

      private CallbackEventBridge() {}

      private void CallbackInternal(IAsyncResult result)
      {
        CallbackComplete(result);
      }

      public AsyncCallback Callback
      {
        get { return new AsyncCallback(CallbackInternal); }
      }

      public static CallbackEventBridge Create()
      {
        return new CallbackEventBridge();
      }
    }
'@
}
$sb = {
  param($ar)
  $e = $ar.AsyncState.e
  $u = $ar.AsyncState.u
  $b = $u.EndReceive($ar, [ref]$e)
  $s = [System.Text.Encoding]::ASCII.GetString($b)
  Write-Host $s
  $ar.AsyncState.completed = $true
}
$bridge = [CallbackEventBridge]::Create()
Register-ObjectEvent -InputObject $bridge -EventName CallbackComplete -Action $sb > $null
$p = 17042
$e = New-Object System.Net.IPEndPoint ([System.Net.IPAddress]::Any, $p)
$u = New-Object System.Net.Sockets.UdpClient $p
$state = @{e = $e; u = $u; completed = $true}
try
{
  for()
  {
    if( $state.completed )
    {
      $state.completed = $false
      [void]$u.BeginReceive($bridge.Callback, $state)
    }
    if ( [System.Console]::KeyAvailable )
    {
      $x = [System.Console]::ReadKey($true)
      if ( $x.key -eq [System.ConsoleKey]::F12 )
      {
        Write-Host 'Exit with F12'
        break
      }
    }
    [System.Threading.Thread]::Sleep(100)
  }
}
finally
{
  $u.Close()
}

Подробнее оКласс CallbackEventouBridge в статье PowerShell 2.0 - асинхронные обратные вызовы из .NET . Автор: Oisin Grehan.

Обе версии можно протестировать с помощью следующего фрагмента кода:

$p = 17042
$u = New-Object System.Net.Sockets.UdpClient
$b = [System.Text.Encoding]::ASCII.GetBytes('Is anybody there')
$u.Connect('localhost', $p)
[void]$u.Send($b, $b.Length)
$u.Close()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...