【问题标题】:Windows UWP Web Service Discovery on LAN局域网上的 Windows UWP Web 服务发现
【发布时间】:2015-08-07 18:11:42
【问题描述】:

我正在尝试为本地网络上的客户端构建 Web 服务。对于该服务,我可以针对任何版本的 .NET Framework。客户端是移动 Windows 设备,我想使用通用 Windows 平台 (UWP) 作为目标框架。

该服务将在具有不同网络地址的多台机器上运行。我的目标是客户端一旦连接到该本地网络,就可以自动检测到该服务。我想避免用户输入任何 IP 地址。但我能找到的所有样本都使用硬编码的服务 URL。由于我没有 DNS-Server,我必须将 service-ip-address 输入(或硬编码)到客户端。

目前我正在使用 UDPDiscoveryEndpoint 运行 WCF 服务,这正是我想要的。但不幸的是,WCF 的那部分(System.ServiceModel.Discovery 命名空间)在 WinRT 上不可用,并且在通用 Windows 平台上也不支持。我不必使用 WCF;任何具有服务发现功能的替代库都是完美的。

所以这是我的问题:有没有办法在 WinRT/UWP 应用程序中的本地网络上进行服务发现?我尝试了 ASP.NET Web API 和 SignalR,但似乎这个基于 HTTP 的服务/框架根本不支持发现。

谢谢!

【问题讨论】:

    标签: c# web-services wcf windows-runtime win-universal-app


    【解决方案1】:

    在 UWP 中,您可以使用 PeerFinder 类来发现 LAN 中应用程序的其他实例。

    我知道这不完全是服务发现,它只是对等发现,但对于您的场景来说应该足够了。只需将应用程序的一个实例用作与其他实例通信的“服务”。

    您可以使用它来查找您的对等点并创建一个套接字连接:

        PeerFinder.DisplayName = "Doru " + Guid.NewGuid().ToString();
    
        PeerFinder.ConnectionRequested += PeerFinder_ConnectionRequested;
    
        PeerFinder.Start();
    
        private async void PeerFinder_ConnectionRequested(object sender, ConnectionRequestedEventArgs args)
        {
            PeerInformation peer = args.PeerInformation;
    
            StreamSocket socket = await PeerFinder.ConnectAsync(peer);
        }
    

    如需更深入地了解 Peer Discovery 的工作原理,请查看 this 链接 [第 6 分钟 30 分钟]。

    【讨论】:

      【解决方案2】:

      我已经设法在 UWP 中使用套接字和广播消息进行 Web 服务发现。

      请查看my answer了解更多详情。

      编辑 - 正如@naveen-vijay 所建议的,我发布了一个更完整的答案,而不仅仅是一个解决方案的链接。

      每个 WS 都会监听一个特定的端口,等待一些广播消息搜索在 LAN 中运行的 WS。 WS实现是win32,需要的代码是这样的:

      private byte[] dataStream = new byte[1024];
      private Socket serverSocket;
      private void InitializeSocketServer(string id)
      {
          // Sets the server ID
          this._id = id;
          // Initialise the socket
          serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
          // Initialise the IPEndPoint for the server and listen on port 30000
          IPEndPoint server = new IPEndPoint(IPAddress.Any, 30000);
          // Associate the socket with this IP address and port
          serverSocket.Bind(server);
          // Initialise the IPEndPoint for the clients
          IPEndPoint clients = new IPEndPoint(IPAddress.Any, 0);
          // Initialise the EndPoint for the clients
          EndPoint epSender = (EndPoint)clients;
          // Start listening for incoming data
          serverSocket.BeginReceiveFrom(this.dataStream, 0, this.dataStream.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveData), epSender);
      }
      
      private void ReceiveData(IAsyncResult asyncResult)
      {
          // Initialise the IPEndPoint for the clients
          IPEndPoint clients = new IPEndPoint(IPAddress.Any, 0);
          // Initialise the EndPoint for the clients
          EndPoint epSender = (EndPoint)clients;
          // Receive all data. Sets epSender to the address of the caller
          serverSocket.EndReceiveFrom(asyncResult, ref epSender);
          // Get the message received
          string message = Encoding.UTF8.GetString(dataStream);
          // Check if it is a search ws message
          if (message.StartsWith("SEARCHWS", StringComparison.CurrentCultureIgnoreCase))
          {
              // Create a response messagem indicating the server ID and it's URL
              byte[] data = Encoding.UTF8.GetBytes($"WSRESPONSE;{this._id};http://{GetIPAddress()}:5055/wsserver");
              // Send the response message to the client who was searching
              serverSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, epSender, new AsyncCallback(this.SendData), epSender);
          }
          // Listen for more connections again...
          serverSocket.BeginReceiveFrom(this.dataStream, 0, this.dataStream.Length, SocketFlags.None, ref epSender, new AsyncCallback(this.ReceiveData), epSender);
      }
      
      private void SendData(IAsyncResult asyncResult)
      {
          serverSocket.EndSend(asyncResult);
      }
      

      客户端实现是 UWP。我创建了以下类来进行搜索:

      public class WSDiscoveryClient
      {
          public class WSEndpoint
          {
              public string ID;
              public string URL;
          }
      
          private List<WSEndpoint> _endPoints;
          private int port = 30000;
          private int timeOut = 5; // seconds
      
          /// <summary>
          /// Get available Webservices
          /// </summary>
          public async Task<List<WSEndpoint>> GetAvailableWSEndpoints()
          {
              _endPoints = new List<WSEndpoint>();
      
              using (var socket = new DatagramSocket())
              {
                  // Set the callback for servers' responses
                  socket.MessageReceived += SocketOnMessageReceived;
                  // Start listening for servers' responses
                  await socket.BindServiceNameAsync(port.ToString());
      
                  // Send a search message
                  await SendMessage(socket);
                  // Waits the timeout in order to receive all the servers' responses
                  await Task.Delay(TimeSpan.FromSeconds(timeOut));
              }
              return _endPoints;
          }
      
          /// <summary>
          /// Sends a broadcast message searching for available Webservices
          /// </summary>
          private async Task SendMessage(DatagramSocket socket)
          {
              using (var stream = await socket.GetOutputStreamAsync(new HostName("255.255.255.255"), port.ToString()))
              {
                  using (var writer = new DataWriter(stream))
                  {
                      var data = Encoding.UTF8.GetBytes("SEARCHWS");
                      writer.WriteBytes(data);
                      await writer.StoreAsync();
                  }
              }
          }
      
          private async void SocketOnMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
          {
              // Creates a reader for the incoming message
              var resultStream = args.GetDataStream().AsStreamForRead(1024);
              using (var reader = new StreamReader(resultStream))
              {
                  // Get the message received
                  string message = await reader.ReadToEndAsync();
                  // Cheks if the message is a response from a server
                  if (message.StartsWith("WSRESPONSE", StringComparison.CurrentCultureIgnoreCase))
                  {
                      // Spected format: WSRESPONSE;<ID>;<HTTP ADDRESS>
                      var splitedMessage = message.Split(';');
                      if (splitedMessage.Length == 3)
                      {
                          var id = splitedMessage[1];
                          var url = splitedMessage[2];
                          _endPoints.Add(new WSEndpoint() { ID = id, URL = url });
                      }
                  }
              }
          }
      }
      

      【讨论】:

      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      • @naveen-vijay,感谢您为我指出。我刚刚编辑了我的答案。对不起,我是新来提供答案的。如果我又做错了,请告诉我。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-05
      • 1970-01-01
      • 1970-01-01
      • 2016-10-31
      相关资源
      最近更新 更多