(UDP) связь между UWP и WPF - PullRequest
       26

(UDP) связь между UWP и WPF

0 голосов
/ 21 марта 2019

У меня есть два приложения (одно UWP и одно WPF), работающие на одной машине, которые должны взаимодействовать следующим образом: Приложение WPF считывает данные с USB-порта и отправляет данные в UWP. приложение UWP получает данные и потребляет их.

Теперь я пытался добиться этого, используя UDP в качестве канала связи, но приложение UWP ничего не получает. Если я создаю два приложения UWP, они могут без проблем общаться через UDP. К сожалению, мне нужен WPF!

Я почти уверен, что это очень распространенный сценарий, и должно быть простое решение, но я искал несколько дней, не найдя решения.

Кстати, я нашел похожий вопрос , но речь идет о C ++, пока мне нужно решение C #.

Edit:

Вот минимальный пример, может быть, это поможет пролить свет на проблему.

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 Я пытался использовать библиотеки WinRT, чтобы оба приложения работали с одинаковыми классами. Для этого я

  1. Создан пустой проект WPF
  2. Добавлены ссылки на C: \ Program Files (x86) \ Windows Наборы \ 10 \ UnionMetadata \ 10.0.17763.0 \ Windows.winmd и C: \ Program Files (x86) \ Справочные сборки \ Microsoft \ Framework.NETCore \ v4.5 \ System.Runtime.WindowsRuntime.dll

Теперь я могу использовать следующие пространства имен в своем приложении WPF:

  • с использованием Windows.Networking;
  • с использованием Windows.Networking.Sockets;
  • с использованием 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();
                    }
                }
            }


        }

    }
}

1 Ответ

0 голосов
/ 25 марта 2019

@ XavierXie-MSFT не является дубликатом.Я действительно нашел ответ сам:

В результате изоляции сети Windows не разрешает устанавливать сокет-соединение (Sockets или WinSock) между двумя приложениями UWP, работающими на одной машине;будь то через локальный адрес обратной связи (127.0.0.0) или путем явного указания локального IP-адреса.Подробнее о механизмах, с помощью которых приложения UWP могут взаимодействовать друг с другом, см. В разделе Связь между приложениями.

Источник: https://docs.microsoft.com/en-us/windows/uwp/networking/sockets

Так что, по-видимому, этоэто "особенность", а не ошибка.Хотя, ИМХО, Microsoft застрелилась в ногу ... опять.Как они могли подумать о блокировке запросов localhost! ??

Во всяком случае, чтобы обойти проблему, я нашел другое решение: я использую службы приложений (проверьте это 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 (соответственно WPF) хочет связаться с WPF (соответственно UWP), он отправляет сообщение в фоновую службу. Фоновая служба пересылает сообщение в WPF (соответственно UWP), получает ответ и пересылает ответ обратно в UWP.(соответственно WPF).

Теперь я столкнулся с новой проблемой: после успешного завершения AppServiceConnection из WPF закрываетсяотправил 226 сообщений в UWP.Тем не менее, WPF продолжает получать сообщения от UWP.Возможно, этот пост поможет мне исправить эту новую проблему (я буду держать вас в курсе): UWP AppServiceConnection - SendResponseAsync возвращает AppServiceResponseStatus.Failure

...