多方法獲取網絡時間


轉自:http://blog.csdn.net/xiaoxian8023/article/details/7250385

在做YH維護的時候,偶爾會碰到這樣的問題:電腦的非正常關機導致系統時間出錯(變為了2002-1-1),從而影響到項目系統的使用。尤其是設計到money的系統,如果時間錯誤,可能會導致無法想象的后果。所以我們可能需要用系統和網絡的雙重驗證。

 

       通過收集、修改、優化和測試,剔除了一些錯誤的和速度超慢的,只剩下了4種可行的方案。這些方案中主要有3類:

          一、通過向某網站發送請求,獲取服務器響應請求的時間

          二、獲某時間網頁的html或xml碼,讀取其中的時間。

          三、通過向某授時服務器發送請求,獲取網絡時間

我把這些方法封裝到了一個類庫里了。

下面是具體的類:NetTime類(包含了多種獲取網絡時間的方法,標有速度),需要添加引用:COM-Microsoft Xml 3.0

[csharp]  view plaincopy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using MSXML2;  
  6. using System.IO;  
  7. using System.Net;  
  8. using System.Net.Sockets;  
  9. using System.Text.RegularExpressions;  
  10. using System.IO.Compression;  
  11. using System.Xml;  
  12.   
  13.   
  14. namespace WebTime  
  15. {  
  16.     /// <summary>  
  17.     /// 網絡時間  
  18.     /// </summary>  
  19.     public class NetTime  
  20.     {  
  21.         #region 獲取標准北京時間1 速度100ms  
  22.         /// <summary>  
  23.         /// [1].獲取標准北京時間1,讀取http://www.beijing-time.org/time.asp  
  24.         /// </summary>  
  25.         /// <returns></returns>  
  26.         public  DateTime GetBeijingTime()  
  27.         {  
  28.             #region  格式  
  29.             // t0=new Date().getTime(); nyear=2012; nmonth=2; nday=11;  
  30.             // nwday=6; nhrs=0; nmin=23; nsec=0;     
  31.             #endregion  
  32.             DateTime dt;  
  33.             WebRequest wrt = null;  
  34.             WebResponse wrp = null;  
  35.             try  
  36.             {  
  37.                 wrt = WebRequest.Create("http://www.beijing-time.org/time.asp");  
  38.                 wrp = wrt.GetResponse();  
  39.   
  40.                 string html = string.Empty;  
  41.                 using (Stream stream = wrp.GetResponseStream())  
  42.                 {  
  43.                     using (StreamReader sr = new StreamReader(stream, Encoding.UTF8))  
  44.                     {  
  45.                         html = sr.ReadToEnd();  
  46.                     }  
  47.                 }  
  48.   
  49.                 string[] tempArray = html.Split(';');  
  50.                 for (int i = 0; i < tempArray.Length; i++)  
  51.                 {  
  52.                     tempArray[i] = tempArray[i].Replace("\r\n", "");  
  53.                 }  
  54.   
  55.                 string year = tempArray[1].Split('=')[1];  
  56.                 string month = tempArray[2].Split('=')[1];  
  57.                 string day = tempArray[3].Split('=')[1];  
  58.                 string hour = tempArray[5].Split('=')[1];  
  59.                 string minite = tempArray[6].Split('=')[1];  
  60.                 string second = tempArray[7].Split('=')[1];  
  61.                 //for (int i = 0; i < tempArray.Length; i++)  
  62.                 //{  
  63.                 //    tempArray[i] = tempArray[i].Replace("\r\n", "");  
  64.                 //}  
  65.   
  66.                 //string year = tempArray[1].Substring(tempArray[1].IndexOf("nyear=") + 6);  
  67.                 //string month = tempArray[2].Substring(tempArray[2].IndexOf("nmonth=") + 7);  
  68.                 //string day = tempArray[3].Substring(tempArray[3].IndexOf("nday=") + 5);  
  69.                 //string hour = tempArray[5].Substring(tempArray[5].IndexOf("nhrs=") + 5);  
  70.                 //string minite = tempArray[6].Substring(tempArray[6].IndexOf("nmin=") + 5);  
  71.                 //string second = tempArray[7].Substring(tempArray[7].IndexOf("nsec=") + 5);  
  72.                 dt = DateTime.Parse(year + "-" + month + "-" + day + " " + hour + ":" + minite + ":" + second);  
  73.             }  
  74.             catch (WebException)  
  75.             {  
  76.                 return DateTime.Parse("2011-1-1");  
  77.             }  
  78.             catch (Exception)  
  79.             {  
  80.                 return DateTime.Parse("2011-1-1");  
  81.             }  
  82.             finally  
  83.             {  
  84.                 if (wrp != null)  
  85.                     wrp.Close();  
  86.                 if (wrt != null)  
  87.                     wrt.Abort();  
  88.             }  
  89.             return dt;  
  90.         }  
  91.         #endregion  
  92.  
  93.         #region 獲取網站響應請求的時間,速度200ms  
  94.         /// <summary>  
  95.         /// [2]獲取網站響應請求的時間,速度200ms  
  96.         /// </summary>  
  97.         /// <param name="hUrl">網址</param>  
  98.         /// <returns>DateTime</returns>  
  99.         /// <remarks></remarks>  
  100.         public DateTime GetNetTime( string hUrl)  
  101.         {  
  102.             string datetxt = null;         //請求回應的時間  
  103.             string[] date1 = null;         //分割后的星期和日期  
  104.             string date2 = "";              //分割后的日期和GMT  
  105.             string[] date3 = null;         //最終成型的日期  
  106.             DateTime nTime  =DateTime.Today ;   
  107.             string localtime = "";  
  108.             string mon = "";  
  109.   
  110.             XMLHTTP objHttp = new XMLHTTP();  
  111.   
  112.             objHttp.open("GET", hUrl, false);  
  113.   
  114.             try  
  115.             {  
  116.                 objHttp.send();  
  117.   
  118.                 //獲取網站回應請求的日期時間。如: Wed, 08 Feb 2012 06:34:58 GMT  
  119.                 datetxt = objHttp.getResponseHeader("Date");  
  120.   
  121.                 //分割時間  
  122.                 date1 = datetxt.Split(',');  
  123.   
  124.             }  
  125.             catch (Exception ex)  
  126.             {  
  127.                 throw ex;  
  128.             }  
  129.   
  130.             //  
  131.             if (date1 ==null )  
  132.             {  
  133.                 localtime = "網絡驗證失敗,請重新啟動或檢查網絡設置";  
  134.             }  
  135.             else if (date1.Length  < 1)  
  136.             {  
  137.                 localtime = "網絡驗證失敗,請重新啟動或檢查網絡設置";  
  138.             }  
  139.             else  
  140.             {  
  141.                 //將時間中的GMT去掉  
  142.                 date2 = date1[1].Replace("GMT", "");  
  143.                   
  144.                 //如: 08 Feb 2012 06:34:58 GMT  
  145.                 date3 = date2.Split(' ');  
  146.                 //如: 08 Feb 2012 06:34:58   
  147.   
  148.                 switch (date3[2])  
  149.                 {  
  150.                     case  "Jan":  
  151.                         mon = "01";  
  152.                         break;  
  153.                     case "Feb":  
  154.                         mon = "02";  
  155.                         break;  
  156.                     case "Mar":  
  157.                         mon = "03";  
  158.                         break;  
  159.                     case "Apr":  
  160.                         mon = "04";  
  161.                         break;  
  162.                     case "May":  
  163.                         mon = "05";  
  164.                         break;  
  165.                     case "Jun":  
  166.                         mon = "06";  
  167.                         break;  
  168.                     case "Jul":  
  169.                         mon = "07";  
  170.                         break;  
  171.                     case "Aug":  
  172.                         mon = "08";  
  173.                         break;  
  174.                     case "Sep":  
  175.                         mon = "09";  
  176.                         break;  
  177.                     case "Oct":  
  178.                         mon = "10";  
  179.                         break;  
  180.                     case "Nov":  
  181.                         mon = "11";  
  182.                         break;  
  183.                     case "Dec":  
  184.                         mon = "12";  
  185.                         break;  
  186.                 }  
  187.   
  188.                 //最終反饋是日期和時間  
  189.                 localtime = date3[3] + "/" + mon + "/" + date3[1] + " " + date3[4];  
  190.   
  191.                 //獲取的協調世界時  
  192.                 DateTime sTime = Convert.ToDateTime(localtime);  
  193.   
  194.                 //轉換為當前計算機所處時區的時間,即東八區時間  
  195.                nTime = TimeZone.CurrentTimeZone.ToLocalTime(sTime);  
  196.             }  
  197.             objHttp = null;  
  198.             return nTime;  
  199.         }  
  200.         #endregion  
  201.  
  202.         #region 獲取標准北京時間3,速度500ms-1500ms  
  203.         /// <summary>  
  204.         /// [3]獲取標准北京時間2 ,讀取(xml)http://www.time.ac.cn/timeflash.asp?user=flash  
  205.         /// </summary>  
  206.         /// <returns></returns>  
  207.         public DateTime GetStandardTime()  
  208.         {  
  209.             #region  文件格式  
  210.             /// //<?xml version="1.0" encoding="GB2312" ?>               
  211.             //- <ntsc>              
  212.             //- <time>             
  213.             //  <year>2011</year>          
  214.             //  <month>7</month>          
  215.             //  <day>10</day>            
  216.             //  <Weekday />     
  217.             //  <hour>19</hour>          
  218.             //  <minite>45</minite>          
  219.             //  <second>37</second>           
  220.             //  <Millisecond />          
  221.             //  </time>           
  222.             //  </ntsc>      
  223.             #endregion  
  224.   
  225.             DateTime dt;  
  226.             WebRequest wrt = null;  
  227.             WebResponse wrp = null;  
  228.             try  
  229.             {  
  230.                 wrt = WebRequest.Create("http://www.time.ac.cn/timeflash.asp?user=flash");  
  231.                 wrt.Credentials = CredentialCache.DefaultCredentials;  
  232.                   
  233.                 wrp = wrt.GetResponse();  
  234.                 StreamReader sr = new StreamReader(wrp.GetResponseStream(), Encoding.UTF8);  
  235.                 string html = sr.ReadToEnd();  
  236.                 sr.Close();  
  237.                 wrp.Close();  
  238.                   
  239.                 //int yearIndex = html.IndexOf("<year>") ;  
  240.                 //int secondIndex = html.IndexOf("</second>");  
  241.                 //html = html.Substring(yearIndex, secondIndex - yearIndex);  
  242.                 html = html.Substring(51, 109);  
  243.   
  244.                 string[] s1 = html.Split(new char[2] { '<', '>' });  
  245.                 string year = s1[2];  
  246.                 string month = s1[6];  
  247.                 string day = s1[10];  
  248.                 string hour = s1[18];  
  249.                 string minite = s1[22];  
  250.                 string second = s1[26];  
  251.                   
  252.                 dt = DateTime.Parse(year + "-" + month + "-" + day + " " + hour + ":" + minite + ":" + second);  
  253.             }  
  254.             catch (WebException)  
  255.             {  
  256.                 return DateTime.Parse("0001-1-1");  
  257.             }  
  258.             catch (Exception)  
  259.             {  
  260.                 return DateTime.Parse("0001-1-1");  
  261.             }  
  262.             finally  
  263.             {  
  264.                 if (wrp != null)  
  265.                     wrp.Close();  
  266.                 if (wrt != null)  
  267.                     wrt.Abort();  
  268.             }  
  269.             return dt;  
  270.         }  
  271.         #endregion  
  272.                  
  273.         #region 訪問標准校時服務器端口獲取網絡時間 速度:1000-2000ms  
  274.         /// <summary>  
  275.         /// 獲取網絡時間,通過標准校時服務器  
  276.         /// </summary>  
  277.         /// <param name="HostName">主機名</param>  
  278.         /// <param name="PortNum">端口號</param>  
  279.         /// <returns>DateTime</returns>  
  280.         public DateTime GetInternetTime(string HostName, int PortNum)  
  281.         {  
  282.             DateTime official, localtime;  
  283.             string returndata = null;  
  284.             string[] dates = new string[4];  
  285.             string[] times = new string[4];  
  286.             string[] tokens = new string[11];  
  287.   
  288.             TcpClient tcpclient = new TcpClient();  
  289.             try  
  290.             {  
  291.                 tcpclient.Connect(HostName, PortNum);  
  292.   
  293.                 NetworkStream networkStream = tcpclient.GetStream();  
  294.                 if (networkStream.CanWrite && networkStream.CanRead)  
  295.                 {  
  296.                     Byte[] sendBytes = Encoding.ASCII.GetBytes("Hello");  
  297.                     networkStream.Write(sendBytes, 0, sendBytes.Length);  
  298.                     byte[] bytes = new byte[tcpclient.ReceiveBufferSize];  
  299.                     networkStream.Read(bytes, 0, (int)tcpclient.ReceiveBufferSize);  
  300.                     returndata = Encoding.ASCII.GetString(bytes);  
  301.                 }  
  302.                 tcpclient.Close();  
  303.             }  
  304.             catch (Exception excep)  
  305.             {  
  306.                 throw excep;  
  307.             }  
  308.   
  309.             tokens = returndata.Split(' ');  
  310.             dates = tokens[1].Split('-');  
  311.             times = tokens[2].Split(':');  
  312.   
  313.             official = new DateTime(Int32.Parse(dates[0]) + 2000, Int32.Parse(dates[1]), Int32.Parse(dates[2]),  
  314.                     Int32.Parse(times[0]), Int32.Parse(times[1]), Int32.Parse(times[2]));  
  315.             localtime = TimeZone.CurrentTimeZone.ToLocalTime(official);  
  316.             return localtime;  
  317.   
  318.         }  
  319.         #endregion  
  320.   
  321.     }  
  322.   
  323. }  


先說一下NetTime類,4個方法,

       第一個方法GetBeijingTime()速度最快,100ms的反應時間,快得沒話說,不過在跟其他校時網比較時間時,它的時間比別的校時網站時間要提前10s。

       第二個方法GetNetTime(string Url),反應時間取決於你訪問的網頁,我這里用的是百度。通過查資料,百度的平均加載速度為:0.48s(2007年),而Google的加載速度為:0.48s(2007年0.87s)。這2個都可以,當然也可以用網易163或者其他的。推薦用這個。我用的Google,反應時間為200ms左右。完全可以滿足你的一般需求。

       第三個方法GetStandardTime(),網站的加載速度為0.55s。但是處理起來有點費時,反應時間在500-1500ms。

       第四個方法GetInternetTime(string HostName,int PortNum),同樣取決於授時服務器,我這里用的是time-a.timefreq.bldrdoc.gov,端口號為13,反應時間在1000-2000ms。

網絡時間應用舉例:

[csharp]  view plaincopy
  1. private void timer2_Tick(object sender, EventArgs e)  
  2. {  
  3.     //速度100ms             
  4.     try  
  5.     {  
  6.         NetTime t = new NetTime();  
  7.         string time = t.GetBeijingTime().ToString();  
  8.         lblNetTime.Text = time;  
  9.     }  
  10.     catch (Exception ex)  
  11.     {  
  12.         lblNetTime.Text = ex.Message;  
  13.     }  
  14.       
  15. }  
  16.   
  17. private void timer3_Tick(object sender, EventArgs e)  
  18. {  
  19.     //速度200ms             
  20.     try  
  21.     {  
  22.         NetTime t = new NetTime();  
  23.         string time = t.GetNetTime("http://www.google.com.hk/").ToString();  
  24.         label3.Text = time;  
  25.     }  
  26.     catch (Exception ex)  
  27.     {                  
  28.           label3.Text = ex.Message ;  
  29.     }           
  30. }  
  31.   
  32. private void timer4_Tick(object sender, EventArgs e)  
  33. {  
  34.     //速度500-1500ms  
  35.     try  
  36.     {  
  37.         NetTime t = new NetTime();  
  38.         string time = t.GetStandardTime().ToString();  
  39.         label4.Text = time;  
  40.     }  
  41.     catch (Exception ex)  
  42.     {  
  43.         label4.Text = ex.Message;  
  44.     }  
  45.       
  46. }  
  47.   
  48. private void timer5_Tick(object sender, EventArgs e)  
  49. {  
  50.     try  
  51.     {                  
  52.         NetTime t = new NetTime();  
  53.         string time = t.GetInternetTime("time-a.timefreq.bldrdoc.gov",13).ToString();  
  54.         label5.Text = time;  
  55.     }  
  56.     catch (Exception ex)  
  57.     {  
  58.         label5.Text = ex.Message;                  
  59.     }  
  60. }  


前面說系統和網絡的雙重驗證,其實只要判斷一下2者 在日期上不同,就用網絡時間來糾正一下本地時間即可。

下面是系統時間類

[csharp]  view plaincopy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Runtime.InteropServices;  
  6.   
  7. namespace WebTime  
  8. {   
  9.     /// <summary>  
  10.     ///  系統時間結構  
  11.     /// </summary>  
  12.     public struct SystemTime  
  13.     {  
  14.         public ushort wyear;            //年  
  15.         public ushort wmonth;           //月  
  16.         public ushort wdayofweek;       //星期  
  17.         public ushort wday;             //日  
  18.         public ushort whour;            //時  
  19.         public ushort wminute;          //分  
  20.         public ushort wsecond;          //秒  
  21.         public ushort wmilliseconds;    //毫秒  
  22.   
  23.         /// <summary>  
  24.         /// 從System.DateTime轉換。  
  25.         /// </summary>  
  26.         /// <param name="time">System.DateTime類型的時間。</param>  
  27.         public void fromDateTime(DateTime time)  
  28.         {  
  29.             wyear = (ushort)time.Year;  
  30.             wmonth = (ushort)time.Month;  
  31.             wdayofweek = (ushort)time.DayOfWeek;  
  32.             wday = (ushort)time.Day;  
  33.             whour = (ushort)time.Hour;  
  34.             wminute = (ushort)time.Minute;  
  35.             wsecond = (ushort)time.Second;  
  36.             wmilliseconds = (ushort)time.Millisecond;  
  37.         }  
  38.   
  39.   
  40.         /// <summary>  
  41.         /// 轉換為system.DateTime類型。  
  42.         /// </summary>  
  43.         /// <returns></returns>  
  44.         public DateTime toDateTime()  
  45.         {  
  46.             return new DateTime(wyear, wmonth, wday, whour, wminute, wsecond, wmilliseconds);  
  47.         }  
  48.   
  49.         /// <summary>  
  50.         /// 靜態方法。轉換為system.DateTime類型。  
  51.         /// </summary>  
  52.         /// <param name="time">systemtime類型的時間。</param>  
  53.         /// <returns></returns>  
  54.         public static DateTime toDateTime(SystemTime time)  
  55.         {  
  56.             return time.toDateTime();  
  57.         }  
  58.     }  
  59.   
  60.     /// <summary>  
  61.     /// 系統時間類  
  62.     /// </summary>  
  63.     public class SysTime  
  64.     {  
  65.         [DllImport("Kernel32.dll ")]  
  66.         public static extern bool SetSystemTime(ref   SystemTime SystemTime);  
  67.         [DllImport("Kernel32.dll ")]  
  68.         public static extern void GetSystemTime(ref   SystemTime SystemTime);  
  69.     }  
  70. }  

其中定義一個系統時間的結構體類型和一個類。SetSystemTime是來設置系統時間,GetSystemTime用來獲取系統時間。

下面是用網絡時間來校對系統時間的源碼:

[csharp]  view plaincopy
  1. private void btnCorretTime_Click(object sender, EventArgs e)  
  2. {  
  3.     NetTime nt = new NetTime();  
  4.   
  5.     //獲取網絡時間  
  6.     string time = nt.GetNetTime("http://www.google.com.hk/").ToString();  
  7.   
  8.     DateTime t=Convert.ToDateTime(time);  
  9.   
  10.   
  11.     //實例化一個系統時間結構體對象  
  12.     SystemTime st = new SystemTime();  
  13.   
  14.      
  15.     //將當前計算機所在時區時間轉化為協調世界時  
  16.     t = TimeZone.CurrentTimeZone.ToUniversalTime(t);  
  17.   
  18.     st.fromDateTime(t);  
  19.   
  20.     //修改系統時間  
  21.     SysTime.SetSystemTime(ref st);  
  22.     MessageBox.Show("時間改為"+ st.toDateTime().ToString());  
  23. }  


       所以只需要給項目系統添加一個通過網絡時間來校對系統時間功能,而其他代碼不用改,還是用系統時間,這樣也符合了開閉原則。

轉載的朋友請說明出處:http://blog.csdn.net/xiaoxian8023/article/details/7250385


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM