UWP DatagramSocket 多播
UWP DatagramSocket Multicast
我设法制作了一个简单的应用程序,用于从多播组发送和接收数据。如果我打开应用程序的 2 个实例(2 个具有相同代码的不同 .sln 文件),我可以发送和接收数据。问题是 5 秒后,如果我从 Client001 发送消息,只有 Client001 会收到消息。但是,如果我在 5 秒内从 Client002(应用程序的第二个实例)发送消息,那么他们都会收到消息。
我有一个 UdpClient 的例子,它工作得很好,但它不再适用于 UWP。
所以总而言之,我怎样才能实现,无论何时(不在 5 秒内)一些客户端发送一条消息,所有其他客户端都收到它?
这是 MainPage.xaml.cs
的代码
namespace Client001
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private DatagramSocket listenerSocket = null;
public string remoteAddress = "224.3.0.5";
HostName remoteHostname;
public string serviceName = "22113";
IOutputStream outputStream;
DataWriter writer;
public MainPage()
{
this.InitializeComponent();
SetupMulticastScenarioUI();
remoteHostname = new HostName(RemoteAddress.Text);
}
private void CloseListenerSocket()
{
if (listenerSocket != null)
{
// DatagramSocket.Close() is exposed through the Dispose() method in C#.
// The call below explicitly closes the socket, freeing the UDP port that it is currently bound to.
listenerSocket.Dispose();
listenerSocket = null;
}
}
// Sets up the UI to display the multicast scenario options.
private void SetupMulticastScenarioUI()
{
RemoteAddress.Text = remoteAddress;
ServiceName.Text = serviceName;
StartListener.Content = "Start listener and join multicast group";
SendMessageButton.IsEnabled = false;
CloseListenerButton.IsEnabled = false;
SendOutput.Text = "";
}
private async void StartListener_Click(object sender, RoutedEventArgs e)
{
listenerSocket = new DatagramSocket();
listenerSocket.Control.MulticastOnly = true;
await listenerSocket.BindServiceNameAsync(ServiceName.Text);
// Join the multicast group to start receiving datagrams being sent to that group.
listenerSocket.JoinMulticastGroup(remoteHostname);
listenerSocket.MessageReceived += MessageReceived;
SendOutput.Text = "Listening on port " + listenerSocket.Information.LocalPort + " and joined to multicast group";
// Enable scenario steps that require us to have an active listening socket.
SendMessageButton.IsEnabled = true;
CloseListenerButton.IsEnabled = true;
outputStream = await listenerSocket.GetOutputStreamAsync(remoteHostname, ServiceName.Text);
writer = new DataWriter(outputStream);
writer.WriteString("Handshake1");
await writer.StoreAsync();
}
private async void SendMessage_Click(object sender, RoutedEventArgs e)
{
writer.WriteString(Message.Text);
await writer.StoreAsync();
}
private void CloseListener_Click(object sender, RoutedEventArgs e)
{
CloseListenerSocket();
// Disable scenario steps that require us to have an active listening socket.
SendMessageButton.IsEnabled = false;
CloseListenerButton.IsEnabled = false;
SendOutput.Text = "";
SendOutput.Text = "Listener closed";
}
async void MessageReceived(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs eventArguments)
{
// Interpret the incoming datagram's entire contents as a string.
uint stringLength = eventArguments.GetDataReader().UnconsumedBufferLength;
string receivedMessage = eventArguments.GetDataReader().ReadString(stringLength);
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
SendOutput.Text = "Received data from remote peer (Remote Address: " +
eventArguments.RemoteAddress.CanonicalName + ", Remote Port: " +
eventArguments.RemotePort + "): \"" + receivedMessage + "\"";
});
}
}
}
这是 MainPage.xaml
的代码
<Page
x:Class="Client001.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Client001"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel>
<TextBlock>Remote Address:</TextBlock>
<TextBox x:Name="RemoteAddress" />
<TextBlock>Service Name:</TextBlock>
<TextBox x:Name="ServiceName" />
<Button x:Name="StartListener" Click="StartListener_Click" Margin="0,10,0,0"/>
<Button x:Name="SendMessageButton" Content="Send 'hello'" Click="SendMessage_Click" Margin="0,10,0,0"/>
<Button x:Name="CloseListenerButton" Content="Close Listener" Click="CloseListener_Click" Margin="0,10,0,0"/>
<TextBlock x:Name="SendOutput" TextWrapping="Wrap" Margin="0,10,0,0"/>
<TextBox x:Name="Message"></TextBox>
</StackPanel>
</Page>
更新: 经过一番搜索,我发现可能是 TTL(生存时间)问题,但我仍然不知道如何解决这个问题.
So in conclusion, how can I achieve, no matter when (not within 5 seconds) some of the clients sends a message, all of the other clients get it?
好像这个问题在最新的WindowsRS1(Build 14393)OS中已经修复了,这里是截图(Gif) :
您可能需要升级OS才能解决。
我设法制作了一个简单的应用程序,用于从多播组发送和接收数据。如果我打开应用程序的 2 个实例(2 个具有相同代码的不同 .sln 文件),我可以发送和接收数据。问题是 5 秒后,如果我从 Client001 发送消息,只有 Client001 会收到消息。但是,如果我在 5 秒内从 Client002(应用程序的第二个实例)发送消息,那么他们都会收到消息。 我有一个 UdpClient 的例子,它工作得很好,但它不再适用于 UWP。 所以总而言之,我怎样才能实现,无论何时(不在 5 秒内)一些客户端发送一条消息,所有其他客户端都收到它?
这是 MainPage.xaml.cs
的代码namespace Client001
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private DatagramSocket listenerSocket = null;
public string remoteAddress = "224.3.0.5";
HostName remoteHostname;
public string serviceName = "22113";
IOutputStream outputStream;
DataWriter writer;
public MainPage()
{
this.InitializeComponent();
SetupMulticastScenarioUI();
remoteHostname = new HostName(RemoteAddress.Text);
}
private void CloseListenerSocket()
{
if (listenerSocket != null)
{
// DatagramSocket.Close() is exposed through the Dispose() method in C#.
// The call below explicitly closes the socket, freeing the UDP port that it is currently bound to.
listenerSocket.Dispose();
listenerSocket = null;
}
}
// Sets up the UI to display the multicast scenario options.
private void SetupMulticastScenarioUI()
{
RemoteAddress.Text = remoteAddress;
ServiceName.Text = serviceName;
StartListener.Content = "Start listener and join multicast group";
SendMessageButton.IsEnabled = false;
CloseListenerButton.IsEnabled = false;
SendOutput.Text = "";
}
private async void StartListener_Click(object sender, RoutedEventArgs e)
{
listenerSocket = new DatagramSocket();
listenerSocket.Control.MulticastOnly = true;
await listenerSocket.BindServiceNameAsync(ServiceName.Text);
// Join the multicast group to start receiving datagrams being sent to that group.
listenerSocket.JoinMulticastGroup(remoteHostname);
listenerSocket.MessageReceived += MessageReceived;
SendOutput.Text = "Listening on port " + listenerSocket.Information.LocalPort + " and joined to multicast group";
// Enable scenario steps that require us to have an active listening socket.
SendMessageButton.IsEnabled = true;
CloseListenerButton.IsEnabled = true;
outputStream = await listenerSocket.GetOutputStreamAsync(remoteHostname, ServiceName.Text);
writer = new DataWriter(outputStream);
writer.WriteString("Handshake1");
await writer.StoreAsync();
}
private async void SendMessage_Click(object sender, RoutedEventArgs e)
{
writer.WriteString(Message.Text);
await writer.StoreAsync();
}
private void CloseListener_Click(object sender, RoutedEventArgs e)
{
CloseListenerSocket();
// Disable scenario steps that require us to have an active listening socket.
SendMessageButton.IsEnabled = false;
CloseListenerButton.IsEnabled = false;
SendOutput.Text = "";
SendOutput.Text = "Listener closed";
}
async void MessageReceived(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs eventArguments)
{
// Interpret the incoming datagram's entire contents as a string.
uint stringLength = eventArguments.GetDataReader().UnconsumedBufferLength;
string receivedMessage = eventArguments.GetDataReader().ReadString(stringLength);
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
SendOutput.Text = "Received data from remote peer (Remote Address: " +
eventArguments.RemoteAddress.CanonicalName + ", Remote Port: " +
eventArguments.RemotePort + "): \"" + receivedMessage + "\"";
});
}
}
}
这是 MainPage.xaml
的代码<Page
x:Class="Client001.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Client001"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel>
<TextBlock>Remote Address:</TextBlock>
<TextBox x:Name="RemoteAddress" />
<TextBlock>Service Name:</TextBlock>
<TextBox x:Name="ServiceName" />
<Button x:Name="StartListener" Click="StartListener_Click" Margin="0,10,0,0"/>
<Button x:Name="SendMessageButton" Content="Send 'hello'" Click="SendMessage_Click" Margin="0,10,0,0"/>
<Button x:Name="CloseListenerButton" Content="Close Listener" Click="CloseListener_Click" Margin="0,10,0,0"/>
<TextBlock x:Name="SendOutput" TextWrapping="Wrap" Margin="0,10,0,0"/>
<TextBox x:Name="Message"></TextBox>
</StackPanel>
</Page>
更新: 经过一番搜索,我发现可能是 TTL(生存时间)问题,但我仍然不知道如何解决这个问题.
So in conclusion, how can I achieve, no matter when (not within 5 seconds) some of the clients sends a message, all of the other clients get it?
好像这个问题在最新的WindowsRS1(Build 14393)OS中已经修复了,这里是截图(Gif) :
您可能需要升级OS才能解决。