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

时间:2012-07-18 11:08:55

标签: sockets udp windows-phone-7.1 asyncsocket

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

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

请注意,以下代码遵循其他论坛上提供的所有建议,即:

  1. 首先将数据包发送到预定目的地,然后收听回复
  2. 不要使用广播而是UDP单播(我可以测试两个设置isBroadcast变量)
  3. 使用SilverLight允许的端口4502
  4. MainPage.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
    }
    }
    

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

1 个答案:

答案 0 :(得分:0)

Silverlight for Windows Phone不需要端口4502,但仅适用于浏览器的Silverlight应用程序..我检查您的代码是因为我遇到了同样的问题。