4

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

  1. Created an empty WPF project
  2. 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();
                    }
                }
            }


        }

    }
}
tremity
  • 61
  • 5
  • UDP is UDP and any software should be able to communicate provided following 1) another app isn't using the port number 2) You are on the same subnet 3) You are using the same type of UDP – jdweng Mar 21 '19 at 09:16
  • I recommend opening a Putty application and get UWP and WPF work with putty before having the two communicate with each other. For UDP to work one end of the connection has to be opened as a listener and the other end a client unless the UDP is Broadcast. – jdweng Mar 21 '19 at 09:18
  • I would suggest that, unless UDP is a must, implement already existing alternatives, check [WCF named pipes](https://stackoverflow.com/questions/1613586/c-sharp-wcf-inter-process-communication). Both UWP and WPF do implement WCF, it should be pretty straightforward to implement. – Cleptus Mar 21 '19 at 09:21
  • @jdweng point 1) and 2) should be ok as I am running on the same machine and using the localhost. What do you mean by "the same type of UDP"? I suspect that the issue might be related to the sandbox that UDP applications are run into. However I am getting very confused from the tests I did: - single UWP application with both "client" and "server" -> they can communicate – tremity Mar 21 '19 at 10:30
  • @bradbury9 thank you for the suggestion. I will look into WCF and let you know if this solves the issue – tremity Mar 21 '19 at 10:32
  • @jdweng point 1) and 2) should be ok as I am running on the same machine and using localhost. What do you mean by "the same type of UDP"? I suspect that the issue might be related to the sandbox that UDP applications are run into. However I am getting very confused from the tests I did: 1)single UWP application with both "client" and "server" -> they communicate 2)two UWP apps (one client and one server) -> they communicate 3)one UWP server and one WPF client-> client messages do not reach the server 4)one UWP server and a UWP-packaged WPF client -> client messages do not reach server – tremity Mar 21 '19 at 10:35
  • Same machine doesn't always mean same subnet. For example if you have Linux on machine often there are issues going between windows and linux. Localhost does always work because some machines have local host the IP of the machine and other have the loopback 172.0.0.1. In this case a Server and a listener should be the same. The confusion comes from the term client have two meanings. At application level you have a Client and Server. At the socket (connection) level you have two UdpClient connecting. One client is configured as listener the other client connects to the listener. – jdweng Mar 21 '19 at 10:47
  • UDP you can have Broadcast and non Broadcast. And Broadcast you can have multicast (224 to 239) and non multicast. – jdweng Mar 21 '19 at 10:58
  • @jdweng I will edit my question and put the code I am using, maybe you can take a look at it and have a better idea of what is causing the issue? – tremity Mar 21 '19 at 11:56
  • The client and server must use the same port number to work. The server must be started first as a listener then the client connects to listener. When client and server are on the same machine the Server listens on IP.Any and the client connects to the IP address of machine. Using localhost doesn't always work because on some machines it is set to loopback address 127.0.0.1 and Net library gives error if you try to connect a client to loopback. – jdweng Mar 21 '19 at 13:32
  • @jdweng did you have the chance to run the code on your machine? does it work for you? The server and the client are communicating on the same port. The "server" listen to one port and the "client" listen to another port. when the client tries to send a message to the server, it sends it to the port that the server is listening on. – tremity Mar 21 '19 at 15:09
  • What are these two lines : private string ClientPortNumber = "1336"; private string ServerPortNumber = "1337"; In the server where are you Starting Listener? It looks like all you did was to initialize the parameters and forgot to start. – jdweng Mar 21 '19 at 15:24
  • @jdweng What you see there is a "Page" in the UWP app. When the app is started, that page is shown. When the page is shown, the callback OnNavigatedTo is fired. As you cans see the OnNavigatedTo starts the server. – tremity Mar 21 '19 at 16:24
  • It is calling the method StartServer() but in the method it is not starting the socket to listen. Where is following : https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener.start?view=netframework-4.7.2 – jdweng Mar 21 '19 at 16:33
  • The link you provided is for TCPListener. I am using a UDP socket. Are you suggesting that I should use TCP instead? I am not following... – tremity Mar 21 '19 at 17:12
  • Possible duplicate of [Problems with UDP in windows 10. UWP](https://stackoverflow.com/questions/36832880/problems-with-udp-in-windows-10-uwp) – Xie Steven Mar 22 '19 at 02:43

1 Answers1

2

@XavierXie-MSFT is not a duplicate. I actually found the answer myself:

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.

Source: https://learn.microsoft.com/en-us/windows/uwp/networking/sockets

So, apparently, this is a "feature" and not a bug. Although, IMHO, Microsoft shot itself in a foot...again. How could they think of blocking localhost requests!??

Anyhow, to come around the problem I found a different solution: I am using App Services (check this out https://learn.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service). So, now I have my UWP app that includes a background app service.

The overall infrastructure can be imagined as follows: UWP <--> background app service <--> WPF

I have been inspired by this: https://csharp.christiannagel.com/2018/10/09/desktopbridge/

The UWP app instantiates an AppServiceConnection to the background service. The WPF app also instantiates an AppServiceConnection to the background service. The background service has two AppServiceConnection: one bound to the UWP app and the other to the WPF app.

When UWP (resp. WPF) wants to communicate with WPF (resp. UWP), it sends a message to the background service. The background service forwards the message to WPF (resp. UWP), gets a response and forward the response back to UWP (resp. WPF).

Now I am facing a new problem, though: the AppServiceConnection of WPF gets closed after it successfully sent 226 messages to UWP. Yet, WPF keeps receiving messages from UWP. Maybe this post could help me to fix this new issue (I will keep you posted): UWP AppServiceConnection - SendResponseAsync returns AppServiceResponseStatus.Failure

tremity
  • 61
  • 5
  • Well, this works only if the WPF app adhears to MSIX packing (essentially making it a UWP) OR can be packaged along with the UWP using Windows Packaging Project. – Nabster Feb 14 '20 at 01:13