【问题标题】:Determine if UDP host is reachable?确定UDP主机是否可达?
【发布时间】:2013-03-07 16:15:48
【问题描述】:

我有一个 Metro 应用程序使用 UDP 通过 wifi 与设备通信。但是,当我断开设备与网络的连接或在设备断开连接的情况下启动应用程序时,什么也没有发生。 ConnectAsync 不会引发异常,应用程序不会引发异常,应用程序运行起来就像没有任何问题一样。 我无法 ping 另一端,但如果我给它一个格式化的字符串,它会响应。该设备当前连接到可以访问互联网的路由器,但我最终计划使用没有互联网访问权限的路由器。我从来没有对 UDP 做过任何事情,所以我在这里不知所措。

这是一个 UDP 侦听器/编写器的实现(取自 Pete Bright 在 10rem.net)

class Network
    {
        private DatagramSocket _socket;
        public bool IsConnected { get; set; }
        public bool recieved;
        public string ret;


        public Network()
        {
            IsConnected = false;

            _socket = new DatagramSocket();

            _socket.MessageReceived += OnSocketMessageReceived;
        }

        public async void Connect(HostName remoteHostName, string remoteServiceNameOrPort)
        {
            try
            {
              await  _socket.ConnectAsync(remoteHostName, remoteServiceNameOrPort);
            }
            catch (Exception e)
            {
                    var msg = new MessageDialog(e.ToString());
                    msg.ShowAsync();
            }
            IsConnected = true;
        }



        private void OnSocketMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
        {
              var reader = args.GetDataReader();

                var count = reader.UnconsumedBufferLength;

                var data = reader.ReadString(count);

                ret = data.Trim();

                recieved = true;

        }


        DataWriter _writer =null;
        public async void SendMessage(string message)
        {
            if (String.IsNullOrEmpty(message)) return;
            if (_writer == null)
            {
                var stream = _socket.OutputStream;
                _writer = new DataWriter(stream);
            }

            _writer.WriteString(message);

            await _writer.StoreAsync();
        }            

    }

【问题讨论】:

  • 您确定ConnectAsync 还没有尝试连接吗?
  • 我认为有一个超时,但它只是在连接时“挂起”。

标签: c# windows-store-apps


【解决方案1】:

UDP 套接字是“无连接”的,因此协议不知道服务器和客户端是否连接。要知道一个连接是否仍然“活动”,您必须实现自己的连接检测。

我可能会推荐阅读 beej 的套接字指南。这是一个很好的阅读,很有趣: http://beej.us/guide/bgnet/

【讨论】:

  • 酷,谢谢。我不确定如何为这种情况编写连接检测方案;如果不推送字符并等待响应,我无法确定设备存在于另一端,并且我无法推送字符,因为ConnectAsyncGetOutputStreamAsync 在没有设备时什么都不做并阻止它下面的所有代码(应该如此)。
【解决方案2】:

正如所说,没有像 tcp/ip 和 sync/ack 等这样的概念来来回通信并确保某些东西在那里。

客户端既没有连接也没有断开连接,只是真正地监听或发送。 因此,话虽如此,您需要从客户端实现接收超时。

UDP 有一些有趣的笑话,因为您发送数据实际上只是将其扔到太空中。接收数据包的顺序也无关紧要,否则您也被困在此处实施自己的方案。

您实际上需要在此处尝试访问设备。如果您关心,那么您可以每 X 秒执行一次。

正如这里所说:How to test a remote UDP Port

(跟我来,下面有一个更好的方法,但想提供多种方法)

您可以使用 UdpClient,在底层套接字上设置接收超时, 连接到该远程服务器/端口,发送一些小消息 (byte[] !) 并调用 Receive。 如果端口关闭,您会收到一个异常,说明连接 被强行关闭(SocketException with 错误代码 10054 = WSAECONNRESET)... 这意味着端口未打开。

但是,我认为更好的方法是实际上就协议 ID 或客户端每 X 秒发送的某些特定数据达成一致。如果收到,则更新您的“客户端已连接”表,否则认为它们已断开连接,直到客户端发送带有协议 id 的数据包。

您可能很容易适应 c# 的 great 系列位于: http://gafferongames.com/networking-for-game-programmers/virtual-connection-over-udp/

我相信您上面的代码也可以重构为仅将 Send() 发送到地址而不是连接,因为确实没有真正的连接。

【讨论】:

  • 那些 UDP 笑话很有教育意义。
【解决方案3】:

为了帮助偶然发现这一点的人:显然我的 google-fu 很弱。 This 展示了如何为 TCP 和 UDP 套接字设置超时。默认行为是永不超时(这与我看到的一致)。

编辑:它不起作用。即使超时 500 毫秒,我仍然看到“没有抛出异常”的相同行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-02
    • 2011-03-03
    • 2013-03-10
    • 2017-08-10
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    相关资源
    最近更新 更多