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



我看了好几天关于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>

主页.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
}
}

SocketClient.cs

  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('');
      }
      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();
  }
  }
}
}

端口4502在Silverlight for Windows Phone中不是必需的,但仅在用于浏览器的Silverlight应用程序中是必需的。。我正在检查你的代码,因为我有同样的问题。

最新更新