I have two applications (one UWP and one WPF) running on the same machine that should communicate as follows: the WPF app reads data from USB port and send the data to UWP. the UWP app gets the data and consume it.
Now, I have been trying to achieve this using UDP as a communication channel but the UWP app does not receive anything. If I create two UWP apps, they can communicate via UDP without problems. Unfortunately, I need the WPF one!
I am pretty sure this is a very common scenario and there should be an easy solution, but I have been searching for days without reaching a solution.
BTW, I found a similar question, but it is about C++ while I need a C# solution.
Edit:
Here is some minimum running example, maybe this helps to shed some light on the issue.
UWP Listener
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 Sender I tried to use the WinRT libriaries so both applications work with the same classes. To do this I
- Created an empty WPF project
- Added references to C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.17763.0\Windows.winmd and C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
Now I am able to use the following namespaces in my WPF application:
- using Windows.Networking;
- using Windows.Networking.Sockets;
- using Windows.Storage.Streams;
Here is the code:
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();
}
}
}
}
}
}