问题描述
我已经看了几天有关 Windows Phone 7 的各种论坛,但是没有人给我一个明确的答案.到目前为止,我还没有收到从通过 wifi 连接到 Windows Phone 7 设备(在模拟器上运行)的计算机发送的 UDP 数据包(既不是广播也不是单播).
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).
显然应该支持 UDP 单播并且下面的代码可以正确运行,但是没有从电话接收到 UDP 数据包.我希望有人可以更正下面的代码.
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:
- 首先将数据包发送到预期目的地,然后侦听回复
- 不要使用广播,而是使用 UDP 单播(我可以测试两个设置 isBroadcast 变量)
- 使用 SilverLight 允许的端口 4502
MainPage.xaml
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
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
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();
}
}
}
}
推荐答案
端口 4502 在 Windows Phone 的 Silverlight 中不是必需的,但仅在浏览器的 Silverlight 应用程序上是必需的.我正在检查您的代码,因为我遇到了同样的问题.
Port 4502 is not required in Silverlight for Windows Phone but only on Silverlight applications for the browser.. I'm checking your code because I have the same problem.
这篇关于Windows Phone 7 通过 wifi 接收 UDP 数据包(广播或单播)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!