Windows Phone 7 receive UDP packet (broadcast or unicast) over wifi
===

I have watched for several days the various forums regarding Windows Phone 7 however none gave me a definitive answer.
So far I have not been able to receive a UDP packet (neither broadcast nor unicast) sent from a computer connected over wifi to a Windows Phone 7 device (running on emulator).

Apparently UDP unicast should be supported and the code below runs correctly, however no UDP packet is received form the phone.
I hope someone can correct the below code.

Notice the below code follows all suggestions so far given on other forums, namely:

 1. Send a packet first to the intended destination and then listen for reply
 2. Do not use broadcast but UDP unicast (I can test both setting isBroadcast variable)
 3. Use port 4502 which is permitted by SilverLight

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