UWP 模擬Ping 請求服務器狀態

  筆者近期作的服務器監控UWP小程序,結果發如今UWP程序的.NET命名空間下取消了Ping的部分,看了諸多資料,以爲多是.NET 4.5 Framework 暫時不支持ICMP。因而筆者想着經過Socket(命名空間保留了的部分)走上層模擬Ping請求,不過這種方式並不能徹底達到效果,緣由在於Socket創建鏈接是須要終結點的,即IP+端口號,而實際上ICMP請求是不須要端口號的,直接經過發送ICMP詢問報文獲取服務器狀態便可。web

  摘記筆者實現的簡易Ping方法:小程序

/// <summary>
        /// 以數據報的消息格式請求鏈接服務器
        /// </summary>
        /// <param name="desEndPoing">終結點</param>
        /// <returns></returns>
        public static async Task<Tuple<string, string, string, string>> DatagramSocketConnect(IPEndPoint desEndPoing)
        {
            // 請求狀態
            string requestStatus = "";
            // 請求耗時
            string requestCost = "";
            // 請求結果
            string color = "";
            // 請求的額外信息
            string others = "";

            // 用來記錄請求耗時
            var s = new System.Diagnostics.Stopwatch();
            s.Start();

            try
            {
                // 使用數據報進行消息傳輸
                using (var UdpClient = new DatagramSocket())
                {
                    // 超時控制
                    CancellationTokenSource cts = new CancellationTokenSource();
                    cts.CancelAfter(1000);                   
                    // HostName 構造須要一個主機名orIP地址(不帶http!)
                    // 異步創建鏈接
                    await UdpClient.ConnectAsync(
                        new Windows.Networking.HostName(desEndPoing.Address.ToString()),
                        desEndPoing.Port.ToString())
                        // 做爲Task任務,添加超時令牌
                        .AsTask(cts.Token);
                    // 停表
                    s.Stop();
                    var remoteIp = UdpClient.Information.RemoteAddress;
                    Debug.WriteLine(String.Format("Success, remote server contacted at IP address {0},and the connecting work cost {1} millsseconds!", 
                        remoteIp, s.ElapsedMilliseconds));

                    #region 修改返回數據
                    requestStatus = "200";
                    requestCost = s.ElapsedMilliseconds.ToString();
                    color = "green";
                    others = String.Format("Success, remote server contacted at IP address {0},and the connecting work cost {1} millsseconds!", 
                        remoteIp, s.ElapsedMilliseconds);

                    #endregion
                    // 釋放鏈接
                    UdpClient.Dispose();
                    return new Tuple<string, string, string, string>(requestStatus, requestCost, color, others);
                }
            }
            // 捕獲自定義超時異常
            catch (TaskCanceledException)
            {
                #region 修改返回數據
                requestStatus = "1000";
                requestCost = s.ElapsedMilliseconds.ToString();
                color = "orange";
                others = "Error: Timeout when connecting (check hostname and port)";
                #endregion
                return new Tuple<string, string, string, string>(requestStatus, requestCost, color, others);
            }
            // 捕獲常見的異常
            catch (Exception ex)
            {
                s.Stop();
                // 查不到對應HostName的服務器
                if (ex.HResult == -2147013895)
                {
                    #region 修改返回數據
                    requestStatus = "0";
                    requestCost = s.ElapsedMilliseconds.ToString();
                    color = "red";
                    others = "Error: No such host is known";
                    #endregion
                    Debug.WriteLine("Error: No such host is known");
                }
                // 請求超時
                else if (ex.HResult == -2147014836)
                {
                    #region 修改返回數據
                    requestStatus = "1000";
                    requestCost = s.ElapsedMilliseconds.ToString();
                    color = "orange";
                    others = "Error: Timeout when connecting (check hostname and port)";
                    #endregion
                    Debug.WriteLine("Error: Timeout when connecting (check hostname and port)");
                }
                // 其餘異常
                else
                {
                    #region 修改返回數據
                    requestStatus = "0";
                    requestCost = s.ElapsedMilliseconds.ToString();
                    color = "red";
                    others = "Error: Exception returned from network stack: " + ex.Message;
                    #endregion
                    Debug.WriteLine("Error: Exception returned from network stack: " + ex.Message);
                }
                return new Tuple<string, string, string, string>(requestStatus, requestCost, color, others);
            }
        }

  上述實現方式中幾個重要須要注意的點:windows

  • 方法體異步(async + await)
  • 異常捕獲處理(可能還存在筆者未捕獲到的異常)
  • 筆者代碼中加入了人爲超時判斷,實際上使用DatagramSocket會本身有超時判斷,大概是5s左右

  上面筆者是用的DatagramSocket實現的,實際上還有不少種Socket也能夠實現:MessageWebSocketStreamSocket等等api

OK,就先記錄到這!服務器

相關文章
相關標籤/搜索