sockets - Windows Phone 7 通过 wifi 接收 UDP 数据包(广播或单播)

标签 sockets udp windows-phone-7.1 asyncsocket

我看了几天有关 Windows Phone 7 的各种论坛,但没有一个给我明确的答案。 到目前为止,我无法接收到从通过 wifi 连接的计算机发送到 Windows Phone 7 设备(在模拟器上运行)的 UDP 数据包(既不是广播也不是单播)。

显然应该支持 UDP 单播并且下面的代码运行正确,但是没有从手机接收到 UDP 数据包。 我希望有人可以更正下面的代码。

注意下面的代码遵循了迄今为止在其他论坛上给出的所有建议,即:

  1. 先发送一个数据包到预定的目的地,然后监听回复
  2. 不使用广播,而是使用 UDP 单播(我可以测试两个设置 isBroadcast 变量)
  3. 使用 SilverLight 允许的 4502 端口

主页.xaml

   <phone:PhoneApplicationPage 
      x:Class="UDPClient.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
      xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
      FontFamily="{StaticResource PhoneFontFamilyNormal}"
      FontSize="{StaticResource PhoneFontSizeNormal}"
      Foreground="{StaticResource PhoneForegroundBrush}"
      SupportedOrientations="Portrait" Orientation="Portrait"
      shell:SystemTray.IsVisible="True">

      <!--LayoutRoot is the root grid where all page content is placed-->
      <Grid x:Name="LayoutRoot" Background="Transparent">
          <Grid.RowDefinitions>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="*"/>
          </Grid.RowDefinitions>

      <!--TitlePanel contains the name of the application and page title-->
          <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
          <TextBlock x:Name="ApplicationTitle" Text="UDP Socket Application" Style="{StaticResource PhoneTextNormalStyle}"/>
          <TextBlock x:Name="PageTitle" Text="Client" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
          </StackPanel>


          <!--ContentPanel - place additional content here-->
          <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,-8,12,8">
          <Grid.ColumnDefinitions>
              <ColumnDefinition Width="Auto"/>
              <!-- Fit to content -->
              <ColumnDefinition Width="Auto"/>
              <!-- Fit to content -->
              <ColumnDefinition Width="Auto"/>
              <!-- Fit to content -->
              <ColumnDefinition Width="*"/>
              <!-- Take up remaining space -->
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
              <RowDefinition Height="Auto"/>
              <!-- Fit to content -->
              <RowDefinition Height="Auto"/>
              <!-- Fit to content -->
              <RowDefinition Height="Auto"/>
              <!-- Fit to content -->
              <RowDefinition Height="*"/>
              <!-- Take up remaining space -->
          </Grid.RowDefinitions>

          <!-- Grid Row 0: Remote Host Input Field >-->
          <TextBlock Grid.Row="0" Grid.Column="0" Text="Host Name:"  
                VerticalAlignment="Center" HorizontalAlignment="Center" 
                FontSize="{StaticResource PhoneFontSizeNormal}" />
          <TextBox x:Name="txtRemoteHost" Grid.Row="0" Grid.Column="1"  Height="70" Width="200" 
              VerticalAlignment="Top" HorizontalAlignment="Left" 
              FontSize="{StaticResource PhoneFontSizeNormal}" Text="192.168.1.3" />

          <!-- Grid Row 1: Echo >-->
          <!-- TextBlock for Echo command label-->
          <TextBlock Grid.Row="1" Grid.Column="0" Text="Text To Echo:" 
                VerticalAlignment="Center" HorizontalAlignment="Center" 
                FontSize="{StaticResource PhoneFontSizeNormal}" />

          <!-- TextBox for Echo command text input-->
          <TextBox x:Name="txtInput" Grid.Row="1" Grid.Column="1" Height="70" Width="200"  
              VerticalAlignment="Top" HorizontalAlignment="Left" 
              FontSize="{StaticResource PhoneFontSizeNormal}" Text="test..." />

          <!-- Button to the right of the input textbox for the Echo command >-->
          <Button x:Name="btnEcho" Grid.Row="1" Grid.Column="2" Height="70"  Width="120" 
              Content="Echo" 
              FontSize="{StaticResource PhoneFontSizeNormal}" Click="btnEcho_Click"/>

          <!-- Grid Row 2: Quote of the Day-->
          <!-- Button for the Quote command >-->
          <Button x:Name="btnGetQuote" Grid.Row="2" Grid.ColumnSpan="4" Height="70" 
              Content="Get Quote of the Day" 
              FontSize="{StaticResource PhoneFontSizeNormal}" Click="btnGetQuote_Click"/>
          <!-- Grid Row 3: Output-->
          <!-- Output TextBox named 'txtOutput' >-->
          <TextBox x:Name="txtOutput" Grid.Row="3" Grid.ColumnSpan="4" Background="Black" BorderBrush="Green" 
              AcceptsReturn="False" Foreground="LightGray" FontFamily="Courier New"  
              IsHitTestVisible="False" FontSize="{StaticResource PhoneFontSizeSmall}" TextWrapping="Wrap" />
          <Button Content="Listen" Grid.Column="1" Grid.ColumnSpan="2" Height="70" HorizontalAlignment="Left" Margin="195,0,0,0" Name="Listenbutton" VerticalAlignment="Top" Width="125" Click="Listenbutton_Click" />
          </Grid>
      </Grid>

      <!--Sample code showing usage of ApplicationBar-->
      <!--<phone:PhoneApplicationPage.ApplicationBar>
          <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
          <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
          <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
          <shell:ApplicationBar.MenuItems>
              <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
              <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
          </shell:ApplicationBar.MenuItems>
          </shell:ApplicationBar>
      </phone:PhoneApplicationPage.ApplicationBar>-->

      </phone:PhoneApplicationPage>

MainPage.xaml.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Net;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Animation;
  using System.Windows.Shapes;
  using Microsoft.Phone.Controls;
  using System.Net.Sockets;
  using System.Threading;


  namespace UDPClient
  {
  public partial class MainPage : PhoneApplicationPage
  {
  // Constructor
  public MainPage()
  {
  InitializeComponent();
  }

  // Constants
  const int ECHO_PORT = 7;  // The Echo protocol uses port 7 in this sample
  const int QOTD_PORT = 17; // The Quote of the Day (QOTD) protocol uses port 17 in this sample
  const int UDP_PORT = 4502;
  /// <summary>
  /// Handle the btnEcho_Click event by sending text to the echo server and outputting the response
  /// </summary>
  private void btnEcho_Click(object sender, RoutedEventArgs e)
  {
  // Clear the log 
  ClearLog();

  // Make sure we can perform this action with valid data
  if (ValidateRemoteHost() && ValidateInput())
  {
      // Instantiate the SocketClient
      SocketClient client = new SocketClient();
      SocketAsyncEventArgs socketEventArg; 

      // Attempt to send our message to be echoed to the echo server
      Log(String.Format("Sending '{0}' to server ...", txtInput.Text), true);
      string result = client.Send(txtRemoteHost.Text, ECHO_PORT, txtInput.Text, false, out socketEventArg);
      Log(result, false);

      // Receive a response from the echo server
      Log("Requesting Receive ...", true);
      result = client.UDPReceive(ECHO_PORT, false);
      Log(result, false);

      // Close the socket connection explicitly
      client.Close();
  }

  }

  private void Listenbutton_Click(object sender, RoutedEventArgs e)
  {
  // Clear the log 
  ClearLog();

  // Make sure we can perform this action with valid data
  if (ValidateRemoteHost())
  {
      // Instantiate the SocketClient
      SocketClient client = new SocketClient();

      // Receive packets
      string result = client.UDPReceive(UDP_PORT, false);
      Log(result, false);
      // Close the socket connection explicitly
      client.Close();
  }
  }

  /// <summary>
  /// Handle the btnGetQuote_Click event by receiving text from the Quote of the Day (QOTD) server and outputting the response
  /// </summary>
  private void btnGetQuote_Click(object sender, RoutedEventArgs e)
  {
  // Clear the log 
  ClearLog();
  // Receive response from the QOTD server
  Log("nothing...", true);;
  }
  }

  #region UI Validation
  /// <summary>
  /// Validates the txtInput TextBox
  /// </summary>
  /// <returns>True if the txtInput TextBox contains valid data, False otherwise</returns>
  private bool ValidateInput()
  {
  // txtInput must contain some text
  if (String.IsNullOrWhiteSpace(txtInput.Text))
  {
      MessageBox.Show("Please enter some text to echo");
      return false;
  }

  return true;
  }

  /// <summary>
  /// Validates the txtRemoteHost TextBox
  /// </summary>
  /// <returns>True if the txtRemoteHost contains valid data, False otherwise</returns>
  private bool ValidateRemoteHost()
  {
  // The txtRemoteHost must contain some text
  if (String.IsNullOrWhiteSpace(txtRemoteHost.Text))
  {
      MessageBox.Show("Please enter a host name");
      return false;
  }

  return true;
  }
  #endregion

  #region Logging
  /// <summary>
  /// Log text to the txtOutput TextBox
  /// </summary>
  /// <param name="message">The message to write to the txtOutput TextBox</param>
  /// <param name="isOutgoing">True if the message is an outgoing (client to server) message, False otherwise</param>
  /// <remarks>We differentiate between a message from the client and server 
  /// by prepending each line  with ">>" and "<<" respectively.</remarks>
  private void Log(string message, bool isOutgoing)
  {
  string direction = (isOutgoing) ? ">> " : "<< ";
  txtOutput.Text += Environment.NewLine + direction + message;
  }

  /// <summary>
  /// Clears the txtOutput TextBox
  /// </summary>
  private void ClearLog()
  {
  txtOutput.Text = String.Empty;
  }
  #endregion
}
}

套接字客户端

  using System;
  using System.Net;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Documents;
  using System.Windows.Ink;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Animation;
  using System.Windows.Shapes;
  using System.Net.Sockets;
  using System.Threading;
  using System.Text;

  namespace UDPClient
  {
  public class SocketClient
  {
  // Cached Socket object that will be used by each call for the lifetime of this class
  Socket _socket = null;
  // Signaling object used to notify when an asynchronous operation is completed
  static ManualResetEvent _clientDone = new ManualResetEvent(false);
  // Define a timeout in milliseconds for each asynchronous call. If a response is not received within this 
  // timeout period, the call is aborted.
  const int TIMEOUT_MILLISECONDS = 1000;
  // The maximum size of the data buffer to use with the asynchronous socket methods
  const int MAX_BUFFER_SIZE = 2048;
  bool isHasSent = false;
  int errorCode = 0;

  /// <summary>
  /// SocketClient Constructor
  /// </summary>
  public SocketClient()
  {
  // The following creates a socket with the following properties:
  // AddressFamily.InterNetwork - the socket will use the IP version 4 addressing scheme to resolve an address
  // SocketType.Dgram - a socket that supports datagram (message) packets
  // PrototcolType.Udp - the User Datagram Protocol (UDP)
  _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  }

  /// <summary>
  /// Send the given data to the server using the established connection
  /// </summary>
  /// <param name="serverName">The name of the server</param>
  /// <param name="portNumber">The number of the port over which to send the data</param>
  /// <param name="data">The data to send to the server</param>
  /// <returns>The result of the Send request</returns>
  public string Send(string serverName, int portNumber, string data, bool isBroadcast, out SocketAsyncEventArgs socketEventArg)
  {
  string response = "Operation Timeout";
  // Create SocketAsyncEventArgs context object

  // We are re-using the _socket object that was initialized in the Connect method
  if (_socket != null)
  {
      socketEventArg = new SocketAsyncEventArgs();
      // Set properties on context object

      System.Diagnostics.Debug.WriteLine("Send(): setting remoteEndPoint");
      if (isBroadcast)
      socketEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Broadcast, portNumber);
      else
      socketEventArg.RemoteEndPoint = new DnsEndPoint(serverName, portNumber);
      System.Diagnostics.Debug.WriteLine("Send(): remoteEndPoint correctly set");

      // Inline event handler for the Completed event.
      // Note: This event handler was implemented inline in order to make this method self-contained.
      socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
      {
      response = e.SocketError.ToString();
      // Unblock the UI thread
      _clientDone.Set();

      isHasSent = true; 
      });

      // Add the data to be sent into the buffer
      byte[] payload = Encoding.UTF8.GetBytes(data);
      socketEventArg.SetBuffer(payload, 0, payload.Length);

      // Sets the state of the event to nonsignaled, causing threads to block
      _clientDone.Reset();

      // Make an asynchronous Send request over the socket
      _socket.SendToAsync(socketEventArg);

      // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
      // If no response comes back within this time then proceed
      _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
  }
  else
  {
      socketEventArg = null;
      response = "Socket is not initialized";
  }

  return response;
  }

  public String UDPReceive(int portNumber, bool isBroadcast)
  {
  SocketAsyncEventArgs socketEventArg;

  System.Diagnostics.Debug.WriteLine("calling Send(\"server\", portNumber, \" \", isBroadcast, out socketEventArg)");
  Send("servern", portNumber, " ", !isBroadcast, out socketEventArg);
  Thread.Sleep(1000);

  while (!isHasSent)
  {
      Thread.Sleep(1);
  }
  System.Diagnostics.Debug.WriteLine("calling Receive(portNumber, isBroadcast, socketEventArg)");
  return Receive(portNumber, isBroadcast, out socketEventArg);
  } 

  /// <summary>
  /// Receive data from the server
  /// </summary>
  /// <param name="portNumber">The port on which to receive data</param>
  /// <returns>The data received from the server</returns>
  public string Receive(int portNumber, bool isBroadcast, out SocketAsyncEventArgs socketEventArg)
  {
  string response = "Operation Timeout";

  // We are receiving over an established socket connection
  if (_socket != null)
  {
      // Create SocketAsyncEventArgs context object
      socketEventArg = new SocketAsyncEventArgs();

      System.Diagnostics.Debug.WriteLine("Receive(): setting remoteEndPoint");
      if (isBroadcast)
      socketEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Broadcast, portNumber);
      else 
      socketEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, portNumber);
      System.Diagnostics.Debug.WriteLine("Receive(): remoteEndPoint correctly set");

      // Setup the buffer to receive the data
      socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
      System.Diagnostics.Debug.WriteLine("Receive(): SetBuffer() correctly called");

      // Inline event handler for the Completed event.
      // Note: This even handler was implemented inline in order to make this method self-contained.
      socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
      {
      if (e.SocketError == SocketError.Success)
      {
          System.Diagnostics.Debug.WriteLine("Receive(): SocketError.Success");
          // Retrieve the data from the buffer
          response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
          response = response.Trim('\0');
      }
      else
      {
          System.Diagnostics.Debug.WriteLine("Receive(): SocketError.Error");
          response = e.SocketError.ToString();
      }
      System.Diagnostics.Debug.WriteLine("Receive(): Set()");
      _clientDone.Set();
      });

      System.Diagnostics.Debug.WriteLine("Receive(): Reset()");
      // Sets the state of the event to nonsignaled, causing threads to block
      _clientDone.Reset();

      try
      {
      // Make an asynchronous Receive request over the socket
      _socket.ReceiveFromAsync(socketEventArg);
      }
      catch (SocketException sockEx)
      {
      Console.WriteLine(sockEx.Message);
      Console.WriteLine(sockEx.ErrorCode);
      Console.WriteLine(sockEx.StackTrace);
      Console.ReadLine();
      System.Diagnostics.Debug.WriteLine("errorCode=" + errorCode + " " + sockEx.Message + sockEx.ErrorCode + sockEx.StackTrace);
      errorCode = 11;
      response += "errorCode=" + errorCode + " " + sockEx.Message + sockEx.ErrorCode + sockEx.StackTrace;
      }
      catch (Exception ex)
      {
      Console.WriteLine(ex.Message);
      Console.WriteLine(ex.StackTrace);
      Console.ReadLine();
      System.Diagnostics.Debug.WriteLine("errorCode="+errorCode+" "+ex.Message + ex.StackTrace);
      errorCode = 22;
      response += "errorCode="+errorCode+" "+ex.Message + ex.StackTrace;
      }
      // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
      // If no response comes back within this time then proceed
      System.Diagnostics.Debug.WriteLine("Receive(): _clientDone.WaitOne(TIMEOUT_MILLISECONDS)");
      _clientDone.WaitOne(TIMEOUT_MILLISECONDS);
  }
  else
  {
      socketEventArg = null;
      response = "Socket is not initialized";
  }
  System.Diagnostics.Debug.WriteLine("Receive(): response = " + response);
  return response;
  }

  /// <summary>
  /// Closes the Socket connection and releases all associated resources
  /// </summary>
  public void Close()
  {
  if (_socket != null)
  {
      _socket.Close();
  }
  }
}
}

最佳答案

Windows Phone 的 Silverlight 不需要端口 4502,但浏览器的 Silverlight 应用程序只需要端口 4502。我正在检查您的代码,因为我遇到了同样的问题。

关于sockets - Windows Phone 7 通过 wifi 接收 UDP 数据包(广播或单播),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11539922/

相关文章:

Perl send() UDP 数据包到多个事件客户端

java - 为什么我的 TCP 系统比 UDP 系统快?

windows-phone-7 - WP7 : Is it possible to intercept the backstack before the journal thumbnail is created/stored

c# - Windows Phone 应用程序有类似 snoop 的工具吗?

c# - 多个 Task<T> 或 IProgress<T> 用于部分完成?

java - python 无法从网络打印解压的 float

c# - 高性能异步等待套接字

javascript - AngularJS 和 Socket.IO - 从服务(此处发出)到 Controller 的返回值未定义 || promise 、异步

c - 处理流媒体服务器

sockets - 在UDP套接字上使用sendto()/recvfrom()而不是connect()/send()/recv()的目的是什么?