UWP 和 WPF 之间的(UDP)通信
(UDP) communication between UWP and WPF
我在同一台机器上有两个应用程序(一个 UWP 和一个 WPF)运行 应该按如下方式通信:
WPF 应用程序从 USB 端口读取数据并将数据发送到 UWP。
UWP 应用获取数据并使用它。
现在,我一直在尝试使用 UDP 作为通信渠道来实现这一点,但 UWP 应用程序没有收到任何东西。
如果我创建两个 UWP 应用程序,它们可以毫无问题地通过 UDP 进行通信。不幸的是,我需要 WPF 一个!
我很确定这是一个非常常见的情况,应该有一个简单的解决方案,但我已经搜索了好几天都没有找到解决方案。
顺便说一句,我找到了一个 ,但它是关于 C++ 的,而我需要一个 C# 解决方案。
编辑:
这里是一些最小的 运行 示例,也许这有助于阐明问题。
UWP 侦听器
using System;
using System.Diagnostics;
using System.IO;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace UDP1_UWP
{
public sealed partial class DatagramSocketPage : Page
{
public DatagramSocketPage()
{
this.InitializeComponent();
}
static string ClientPortNumber = "1336";
static string ServerPortNumber = "1337";
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.StartServer();
}
private async void StartServer()
{
try
{
var serverDatagramSocket = new Windows.Networking.Sockets.DatagramSocket();
serverDatagramSocket.MessageReceived += ServerDatagramSocket_MessageReceived;
this.serverListBox.Items.Add("server is about to bind...");
await serverDatagramSocket.BindServiceNameAsync(DatagramSocketPage.ServerPortNumber);
this.serverListBox.Items.Add(string.Format("server is bound to port number {0}", DatagramSocketPage.ServerPortNumber));
}
catch (Exception ex)
{
Windows.Networking.Sockets.SocketErrorStatus webErrorStatus = Windows.Networking.Sockets.SocketError.GetStatus(ex.GetBaseException().HResult);
this.serverListBox.Items.Add(webErrorStatus.ToString() != "Unknown" ? webErrorStatus.ToString() : ex.Message);
}
}
private async void ServerDatagramSocket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
string request;
using (DataReader dataReader = args.GetDataReader())
{
request = dataReader.ReadString(dataReader.UnconsumedBufferLength).Trim();
}
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.serverListBox.Items.Add(string.Format("server received the request: \"{0}\"", request)));
// Echo the request back as the response.
using (Stream outputStream = (await sender.GetOutputStreamAsync(args.RemoteAddress, DatagramSocketPage.ClientPortNumber)).AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(request);
await streamWriter.FlushAsync();
}
}
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.serverListBox.Items.Add(string.Format("server sent back the response: \"{0}\"", request)));
}
}
}
WPF 发件人
我尝试使用 WinRT 库,因此两个应用程序都可以使用相同的 类。为此,我
- 创建了一个空的 WPF 项目
- 添加了对 C:\Program Files (x86)\Windows 的引用
Kits\UnionMetadata.0.17763.0\Windows.winmd 和 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
现在我可以在我的 WPF 应用程序中使用以下命名空间:
- 使用Windows.Networking;
- 使用 Windows.Networking.套接字;
- 使用 Windows.Storage.Streams;
代码如下:
Program.cs
using System;
using XSensUDPSender.UDP;
namespace XSensUDPServer
{
class Program
{
static void Main(string[] args)
{
UDPClient c = new UDPClient();
c.StartClientAsync();
string text;
do
{
Console.WriteLine("Message to send: ");
text = Console.ReadLine();
c.SendMessageAsync(text);
} while (text != "quit");
}
}
}
UDPClient.cs
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
namespace XSensUDPSender.UDP
{
class UDPClient
{
private DatagramSocket clientDatagramSocket;
private HostName hostName;
private string ClientPortNumber = "1336";
private string ServerPortNumber = "1337";
public UDPClient(string aClientPort = "1336", string aServerPort = "1337")
{
ClientPortNumber = aClientPort;
ServerPortNumber = aServerPort;
}
public async void StartClientAsync()
{
try
{
// Create the DatagramSocket and establish a connection to the echo server.
clientDatagramSocket = new Windows.Networking.Sockets.DatagramSocket();
clientDatagramSocket.MessageReceived += ClientDatagramSocket_MessageReceived;
// The server hostname that we will be establishing a connection to. In this example, the server and client are in the same process.
hostName = new Windows.Networking.HostName("localhost");
Console.WriteLine("CLIENT is about to bind...");
await clientDatagramSocket.BindServiceNameAsync(ClientPortNumber);
Console.WriteLine(string.Format("CLIENT is bound to port number {0}", ClientPortNumber));
}
catch (Exception ex)
{
Windows.Networking.Sockets.SocketErrorStatus webErrorStatus = Windows.Networking.Sockets.SocketError.GetStatus(ex.GetBaseException().HResult);
Debug.WriteLine(webErrorStatus.ToString() != "Unknown" ? webErrorStatus.ToString() : ex.Message);
}
}
private void ClientDatagramSocket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
string response;
using (DataReader dataReader = args.GetDataReader())
{
response = dataReader.ReadString(dataReader.UnconsumedBufferLength).Trim();
Console.WriteLine("CLIENT RECEIVED: " + response);
}
}
public async Task SendMessageAsync(string request)
{
// Send a request to the echo server.
using (var serverDatagramSocket = new Windows.Networking.Sockets.DatagramSocket())
{
using (Stream outputStream = (await serverDatagramSocket.GetOutputStreamAsync(hostName, ServerPortNumber)).AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(request);
await streamWriter.FlushAsync();
}
}
}
}
}
}
@XavierXie-MSFT 不是重复的。其实我自己找到了答案:
As a consequence of network isolation, Windows disallows establishing
a socket connection (Sockets or WinSock) between two UWP apps running
on the same machine; whether that's via the local loopback address
(127.0.0.0), or by explicitly specifying the local IP address. For
details about mechanisms by which UWP apps can communicate with one
another, see App-to-app communication.
来源:https://docs.microsoft.com/en-us/windows/uwp/networking/sockets
所以,显然,这是一个 "feature" 而不是错误。虽然,恕我直言,Microsoft 再次搬起石头砸自己的脚……。他们怎么会想到阻止本地主机请求!??
无论如何,为了解决这个问题,我找到了一个不同的解决方案:我正在使用 App Services
(检查一下 https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service)。
所以,现在我的 UWP 应用程序包含后台应用程序服务。
整体的基础设施可以想象如下:
UWP <--> 后台应用服务 <--> WPF
我受到了启发:https://csharp.christiannagel.com/2018/10/09/desktopbridge/
UWP 应用将 AppServiceConnection 实例化到后台服务。
WPF 应用程序还将 AppServiceConnection 实例化到后台服务。
后台服务有两个 AppServiceConnection:一个绑定到 UWP 应用程序,另一个绑定到 WPF 应用程序。
当UWP (resp. WPF) 想要与WPF (resp. UWP) 通信时,它会向后台服务发送消息。后台服务将消息转发给 WPF(resp. UWP),获取响应并将响应转发回 UWP(resp. WPF)。
不过,现在我面临一个新问题:WPF 的 AppServiceConnection 在成功向 UWP 发送 226 条消息后关闭。然而,WPF 不断接收来自 UWP 的消息。
也许这个 post 可以帮助我解决这个新问题(我会让你 posted):
我在同一台机器上有两个应用程序(一个 UWP 和一个 WPF)运行 应该按如下方式通信: WPF 应用程序从 USB 端口读取数据并将数据发送到 UWP。 UWP 应用获取数据并使用它。
现在,我一直在尝试使用 UDP 作为通信渠道来实现这一点,但 UWP 应用程序没有收到任何东西。 如果我创建两个 UWP 应用程序,它们可以毫无问题地通过 UDP 进行通信。不幸的是,我需要 WPF 一个!
我很确定这是一个非常常见的情况,应该有一个简单的解决方案,但我已经搜索了好几天都没有找到解决方案。
顺便说一句,我找到了一个
编辑:
这里是一些最小的 运行 示例,也许这有助于阐明问题。
UWP 侦听器
using System;
using System.Diagnostics;
using System.IO;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace UDP1_UWP
{
public sealed partial class DatagramSocketPage : Page
{
public DatagramSocketPage()
{
this.InitializeComponent();
}
static string ClientPortNumber = "1336";
static string ServerPortNumber = "1337";
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.StartServer();
}
private async void StartServer()
{
try
{
var serverDatagramSocket = new Windows.Networking.Sockets.DatagramSocket();
serverDatagramSocket.MessageReceived += ServerDatagramSocket_MessageReceived;
this.serverListBox.Items.Add("server is about to bind...");
await serverDatagramSocket.BindServiceNameAsync(DatagramSocketPage.ServerPortNumber);
this.serverListBox.Items.Add(string.Format("server is bound to port number {0}", DatagramSocketPage.ServerPortNumber));
}
catch (Exception ex)
{
Windows.Networking.Sockets.SocketErrorStatus webErrorStatus = Windows.Networking.Sockets.SocketError.GetStatus(ex.GetBaseException().HResult);
this.serverListBox.Items.Add(webErrorStatus.ToString() != "Unknown" ? webErrorStatus.ToString() : ex.Message);
}
}
private async void ServerDatagramSocket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
string request;
using (DataReader dataReader = args.GetDataReader())
{
request = dataReader.ReadString(dataReader.UnconsumedBufferLength).Trim();
}
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.serverListBox.Items.Add(string.Format("server received the request: \"{0}\"", request)));
// Echo the request back as the response.
using (Stream outputStream = (await sender.GetOutputStreamAsync(args.RemoteAddress, DatagramSocketPage.ClientPortNumber)).AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(request);
await streamWriter.FlushAsync();
}
}
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.serverListBox.Items.Add(string.Format("server sent back the response: \"{0}\"", request)));
}
}
}
WPF 发件人 我尝试使用 WinRT 库,因此两个应用程序都可以使用相同的 类。为此,我
- 创建了一个空的 WPF 项目
- 添加了对 C:\Program Files (x86)\Windows 的引用 Kits\UnionMetadata.0.17763.0\Windows.winmd 和 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
现在我可以在我的 WPF 应用程序中使用以下命名空间:
- 使用Windows.Networking;
- 使用 Windows.Networking.套接字;
- 使用 Windows.Storage.Streams;
代码如下:
Program.cs
using System;
using XSensUDPSender.UDP;
namespace XSensUDPServer
{
class Program
{
static void Main(string[] args)
{
UDPClient c = new UDPClient();
c.StartClientAsync();
string text;
do
{
Console.WriteLine("Message to send: ");
text = Console.ReadLine();
c.SendMessageAsync(text);
} while (text != "quit");
}
}
}
UDPClient.cs
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
namespace XSensUDPSender.UDP
{
class UDPClient
{
private DatagramSocket clientDatagramSocket;
private HostName hostName;
private string ClientPortNumber = "1336";
private string ServerPortNumber = "1337";
public UDPClient(string aClientPort = "1336", string aServerPort = "1337")
{
ClientPortNumber = aClientPort;
ServerPortNumber = aServerPort;
}
public async void StartClientAsync()
{
try
{
// Create the DatagramSocket and establish a connection to the echo server.
clientDatagramSocket = new Windows.Networking.Sockets.DatagramSocket();
clientDatagramSocket.MessageReceived += ClientDatagramSocket_MessageReceived;
// The server hostname that we will be establishing a connection to. In this example, the server and client are in the same process.
hostName = new Windows.Networking.HostName("localhost");
Console.WriteLine("CLIENT is about to bind...");
await clientDatagramSocket.BindServiceNameAsync(ClientPortNumber);
Console.WriteLine(string.Format("CLIENT is bound to port number {0}", ClientPortNumber));
}
catch (Exception ex)
{
Windows.Networking.Sockets.SocketErrorStatus webErrorStatus = Windows.Networking.Sockets.SocketError.GetStatus(ex.GetBaseException().HResult);
Debug.WriteLine(webErrorStatus.ToString() != "Unknown" ? webErrorStatus.ToString() : ex.Message);
}
}
private void ClientDatagramSocket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
string response;
using (DataReader dataReader = args.GetDataReader())
{
response = dataReader.ReadString(dataReader.UnconsumedBufferLength).Trim();
Console.WriteLine("CLIENT RECEIVED: " + response);
}
}
public async Task SendMessageAsync(string request)
{
// Send a request to the echo server.
using (var serverDatagramSocket = new Windows.Networking.Sockets.DatagramSocket())
{
using (Stream outputStream = (await serverDatagramSocket.GetOutputStreamAsync(hostName, ServerPortNumber)).AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(request);
await streamWriter.FlushAsync();
}
}
}
}
}
}
@XavierXie-MSFT 不是重复的。其实我自己找到了答案:
As a consequence of network isolation, Windows disallows establishing a socket connection (Sockets or WinSock) between two UWP apps running on the same machine; whether that's via the local loopback address (127.0.0.0), or by explicitly specifying the local IP address. For details about mechanisms by which UWP apps can communicate with one another, see App-to-app communication.
来源:https://docs.microsoft.com/en-us/windows/uwp/networking/sockets
所以,显然,这是一个 "feature" 而不是错误。虽然,恕我直言,Microsoft 再次搬起石头砸自己的脚……。他们怎么会想到阻止本地主机请求!??
无论如何,为了解决这个问题,我找到了一个不同的解决方案:我正在使用 App Services (检查一下 https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service)。 所以,现在我的 UWP 应用程序包含后台应用程序服务。
整体的基础设施可以想象如下: UWP <--> 后台应用服务 <--> WPF
我受到了启发:https://csharp.christiannagel.com/2018/10/09/desktopbridge/
UWP 应用将 AppServiceConnection 实例化到后台服务。 WPF 应用程序还将 AppServiceConnection 实例化到后台服务。 后台服务有两个 AppServiceConnection:一个绑定到 UWP 应用程序,另一个绑定到 WPF 应用程序。
当UWP (resp. WPF) 想要与WPF (resp. UWP) 通信时,它会向后台服务发送消息。后台服务将消息转发给 WPF(resp. UWP),获取响应并将响应转发回 UWP(resp. WPF)。
不过,现在我面临一个新问题:WPF 的 AppServiceConnection 在成功向 UWP 发送 226 条消息后关闭。然而,WPF 不断接收来自 UWP 的消息。
也许这个 post 可以帮助我解决这个新问题(我会让你 posted):