在網站上實現時鐘同步的操作是很常見的。這裡以UDP方式來實現一個。其中會調用到WINAPI
using System ;
using System.Drawing ;
using System.Collections ;
using System.ComponentModel ;
using System.Windows.Forms ;
using System.Data ;
using System.Net ;
using System.Net.Sockets ;
using System.Threading ;
//程式中使用到線程
using System.Text ;
//程式中使用到編碼
namespace UDPTimerServer{
/// <summary>
/// Form1 的摘要說明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.Button button1;
private UdpClient server ;
private IPEndPoint receivePoint ;
private int port = 10000 ;
//定義連接埠號碼
private int ip = 127001 ;
//設定本地IP地址
private Thread startServer ;
/// <summary>
/// 必需的設計器變數。
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows 表單設計器支援所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 調用後添加任何建構函式代碼
//
}
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
protected override void Dispose( bool disposing )
{
try
{
//關閉線程
startServer.Abort ( ) ;
//清除資源
server.Close ( ) ;
}
catch
{
} ;
if ( disposing )
{
if ( components != null )
{
components.Dispose ( ) ;
}
}
base.Dispose ( disposing ) ;
}
#region Windows 表單設計器產生的程式碼
/// <summary>
/// 設計器支援所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內容。
/// </summary>
private void InitializeComponent()
{
this.listBox1 = new System.Windows.Forms.ListBox ( ) ;
this.label1 = new System.Windows.Forms.Label ( ) ;
this.button1 = new System.Windows.Forms.Button ( ) ;
this.SuspendLayout ( ) ;
this.listBox1.ItemHeight = 12 ;
this.listBox1.Location = new System.Drawing.Point ( 14 , 40 ) ;
this.listBox1.Name = "listBox1" ;
this.listBox1.Size = new System.Drawing.Size ( 268 , 220 ) ;
this.listBox1.TabIndex = 0 ;
this.label1.ForeColor = System.Drawing.Color.Red ;
this.label1.Location = new System.Drawing.Point ( 44 , 10 ) ;
this.label1.Name = "label1" ;
this.label1.Size = new System.Drawing.Size ( 210 , 24 ) ;
this.label1.TabIndex = 1 ;
this.label1.Text = "UDP對時伺服器端正在運行......" ;
this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat ;
this.button1.Location = new System.Drawing.Point ( 106 , 278 ) ;
this.button1.Name = "button1" ;
this.button1.Size = new System.Drawing.Size ( 75 , 34 ) ;
this.button1.TabIndex = 2 ;
this.button1.Text = "清除資訊" ;
this.button1.Click += new System.EventHandler ( this.button1_Click ) ;
this.AutoScaleBaseSize = new System.Drawing.Size ( 6 , 14 ) ;
this.ClientSize = new System.Drawing.Size ( 300 , 329 ) ;
this.Controls.AddRange ( new System.Windows.Forms.Control[] {
this.button1 ,
this.listBox1 ,
this.label1} ) ;
this.MaximizeBox = false ;
this.Name = "Form1" ;
this.Text = "UDP對時伺服器端" ;
this.Load += new System.EventHandler ( this.Form1_Load ) ;
this.ResumeLayout ( false ) ;
}
#endregion
/// <summary>
/// 應用程式的主進入點。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
Run();
}
// 請注意:下面代碼中約定客戶機程式發送對時請求資訊到伺服器的8080連接埠號碼。
// 伺服器端程式接收發送到本地8080連接埠號碼的資料就完成了資料接收。
// 為了能夠讓伺服器端程式知道是那台客戶機提出請求和要把對時資訊發送到客戶機的那個連接埠號碼上,
// 用戶端程式對發送的對時請求資訊進行了設計。用戶端的對時請求資訊結構為:
//
// 電腦名稱 + / + 客戶機接收資訊連接埠號碼
//
// 這樣如果用戶端電腦名稱為:greystar,接收伺服器端時間資料的連接埠號碼是1000,
// 則用戶端程式發送的對時請求資料就為:greystar/1000。
//
// 伺服器端程式在接收到用戶端對時請求資料,並進行分析後,
// 就能夠通過UdpClient類的Send方法準確的把伺服器端當前的時間和日期發送到用戶端指定的連接埠號碼上。
// 這樣用戶端程式通過讀取指定的連接埠號碼,就能夠獲得伺服器端當前的時間和日期,
// 從而以此來修正用戶端的時間和日期了。
public void start_server ( )
{
while ( true )
{
//接收從遠程主機發送到本地8080連接埠的資料
byte[] recData = server.Receive ( ref receivePoint ) ;
ASCIIEncoding encode = new ASCIIEncoding ( ) ;
//獲得用戶端請求資料
string Read_str = encode.GetString ( recData ) ;
//提取用戶端的資訊,存放到定義為temp的字串數組中
string[] temp = Read_str.Split ( "/".ToCharArray ( ) ) ;
//顯示連接埠號碼的請求資訊
listBox1.Items.Add ( "時間:"+ DateTime.Now.
ToLongTimeString ( ) + " 接收資訊如下:" ) ;
listBox1.Items.Add ( "客戶機:" + temp[0] ) ;
listBox1.Items.Add ( "連接埠號碼:" + temp[1] ) ;
//發送伺服器端時間和日期
byte[] sendData =encode.GetBytes
( System.DateTime.Now.ToString ( ) ) ;
listBox1.Items.Add ( "發送伺服器時間!" ) ;
//對遠程主機的指定連接埠號碼發送伺服器時間
server.Send ( sendData , sendData.Length ,
temp[0] , Int32.Parse ( temp[1] ) ) ;
}
}
public void Run ( )
{
//利用本地8080連接埠號碼來初始化一個UDP網路服務
server = new UdpClient ( port ) ;
receivePoint = new IPEndPoint ( new IPAddress ( ip ) , port ) ;
//開一個線程
startServer = new Thread ( new ThreadStart ( start_server ) ) ;
//啟動線程
startServer.Start ( ) ;
}
private void button1_Click(object sender, System.EventArgs e)
{
listBox1.Items.Clear ( ) ;
}
}
}
using System;
using System.Drawing;
using System.Collections ;
using System.ComponentModel ;
using System.Windows.Forms ;
using System.Data ;
using System.Net ;
using System.Net.Sockets ;
using System.Runtime.InteropServices ;
//用戶端程式
namespace UDPTimerClient
{
/// <summary>
/// Form1 的摘要說明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.TextBox textBox3;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private UdpClient client ;
//建立UDP網路服務
private IPEndPoint receivePoint ;
private int port = 8080 ;
//定義接收伺服器端程式發送對時資訊對應的連接埠號碼
private string timeString = DateTime.Now.ToString ( ) ;
//存放時間日期資訊字串
private DateTime temp ;
private System.Windows.Forms.Label label3;
//定義一個時間類型,用以修改目前時間和日期
/// <summary>
/// 必需的設計器變數。
/// </summary>
private System.ComponentModel.Container components = null;
[ DllImport ( "Kernel32.dll" )]
private static extern bool SetSystemTime ( SystemTime time ) ;
public Form1()
{
//
// Windows 表單設計器支援所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 調用後添加任何建構函式代碼
//
}
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 表單設計器產生的程式碼
/// <summary>
/// 設計器支援所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內容。
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.textBox3 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button1.Location = new System.Drawing.Point(128, 128);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(112, 40);
this.button1.TabIndex = 0;
this.button1.Text = "擷取";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button2.Location = new System.Drawing.Point(128, 184);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(112, 40);
this.button2.TabIndex = 1;
this.button2.Text = "對時";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(120, 56);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(200, 21);
this.textBox1.TabIndex = 2;
this.textBox1.Text = "";
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(120, 88);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(200, 21);
this.textBox2.TabIndex = 3;
this.textBox2.Text = "";
//
// label1
//
this.label1.Location = new System.Drawing.Point(48, 56);
this.label1.Name = "label1";
this.label1.TabIndex = 4;
this.label1.Text = "本地時間:";
//
// label2
//
this.label2.Location = new System.Drawing.Point(40, 88);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(88, 24);
this.label2.TabIndex = 5;
this.label2.Text = "伺服器時間:";
//
// label3
//
this.label3.Location = new System.Drawing.Point(16, 24);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(112, 23);
this.label3.TabIndex = 6;
this.label3.Text = "設定伺服器位址:";
//
// textBox3
//
this.textBox3.Location = new System.Drawing.Point(120, 24);
this.textBox3.Name = "textBox3";
this.textBox3.Size = new System.Drawing.Size(200, 21);
this.textBox3.TabIndex = 7;
this.textBox3.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(352, 245);
this.Controls.Add(this.textBox3);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.label1);
this.Controls.Add(this.label2);
this.Controls.Add(this.label3);
this.MaximizeBox = false;
this.Name = "Form1";
this.Text = "UDP對時用戶端";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// 應用程式的主進入點。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
[StructLayout(LayoutKind.Sequential )]
public class SystemTime
{
public short year ;
public short Month ;
public short DayOfWeek ;
public short Day ;
public short Hour ;
public short Minute ;
public short Second ;
public short Milliseconds ;
}
//定義系統時間的結構
void Start()
{
client = new UdpClient ( port ) ;
IPAddress a = IPAddress.Parse ( "127001" ) ;
receivePoint = new IPEndPoint ( a , port ) ;
IPAddress HostIP ;
bool continueLoop = true ;
while ( continueLoop )
{
string hostName = Dns.GetHostName ( ) ;
System.Text.ASCIIEncoding encode
= new System.Text.ASCIIEncoding ( ) ;
//定義發送到伺服器端的請求資訊
//請求資訊是一個字串,為用戶端名稱和接收伺服器反饋資訊的連接埠號碼組成的字串
string sendString = hostName + "/" + port.ToString ( ) ;
byte[] sendData = encode.GetBytes ( sendString ) ;
//判斷使用者輸入的是IP地址還是電腦名稱
try
{
HostIP = IPAddress.Parse ( textBox3.Text ) ;
}
catch
{
//如果輸入的是電腦名稱,則按照執行下列代碼。
//發送請求資訊,伺服器連接埠定為10000
client.Send ( sendData , sendData.
Length , textBox3.Text , 10000 ) ;
//接收來自伺服器端的資訊
byte[] recData =
client.Receive ( ref receivePoint ) ;
timeString = encode.GetString ( recData ) ;
client.Close ( ) ;
continueLoop=false ;
return ;
}
//輸入的是IP地址,則執行下列代碼
IPEndPoint host = new IPEndPoint ( HostIP ,10000 ) ;
//發送請求資訊
client.Send ( sendData , sendData.Length , host ) ;
//接收來自伺服器端的資訊
byte[] recData1 = client.Receive ( ref receivePoint ) ;
//擷取伺服器端的時間和日期
timeString = encode.GetString ( recData1 ) ;
client.Close ( ) ;
//退出迴圈
continueLoop=false ;
}
}
private void button1_Click(object sender, System.EventArgs e)
{
Start ( ) ;
textBox1.Text = DateTime.Now.ToString ( ) ;
//顯示用戶端目前時間和日期
textBox2.Text = timeString ;
//顯示伺服器目前時間和日期
}
private void button2_Click(object sender, System.EventArgs e)
{
Start ( ) ;
//把接收來的資料轉換時間日期格式
try
{
temp = DateTime.Parse ( timeString ) ;
}
catch
{
MessageBox.Show ( "錯誤時間" ) ;
return ;
}
//根據得到的時間日期,來定義時間、日期
SystemTime st= new SystemTime ( ) ;
st.year= ( short )temp.Year ;
st.Month= ( short )temp.Month ;
st.DayOfWeek= ( short )temp.DayOfWeek ;
st.Day= ( short )temp.Day ;
st.Hour=Convert.ToInt16 ( temp.Hour ) ;
if ( st.Hour>=12 )
{
st.Hour-= ( short )8 ;
}
else if ( st.Hour >= 8 )
{
st.Hour-= ( short )8 ;
}
else
{
st.Hour+= ( short )16 ;
}
st.Minute=Convert.ToInt16 ( temp.Minute ) ;
st.Second=Convert.ToInt16 ( temp.Second ) ;
st.Milliseconds=Convert.ToInt16 ( temp.Millisecond ) ;
//修改本地端的時間和日期
if ( SetSystemTime ( st ) )
{
MessageBox.Show ( DateTime.Now.ToString ( ) ,"修改成功" ) ;
}
else
MessageBox.Show ( "不成功!" ,"不成功" ) ;
}
}
}