使用UDP实现一个时钟服务器

在网站上实现时钟同步的操作是很常见的。这里以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{
 ///


 /// Form1 的摘要说明。
 ///

 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 ;
  ///


  /// 必需的设计器变量。
  ///

  private System.ComponentModel.Container components = null;

  public Form1()
  {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();

   //
   // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   //
  }

  ///


  /// 清理所有正在使用的资源。
  ///

  protected override void Dispose( bool disposing )
  {
   try
   {
    //关闭线程
    startServer.Abort ( ) ;
    //清除资源
    server.Close ( ) ;
   }
   catch
   {
   } ;
   if (  disposing  )
   {
    if  ( components != null )
    {
     components.Dispose ( ) ;
    }
   }
   base.Dispose (  disposing  ) ;

  }

  #region Windows 窗体设计器生成的代码
  ///


  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  ///

  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

  ///


  /// 应用程序的主入口点。
  ///

  [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
{
 ///


 /// Form1 的摘要说明。
 ///

 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;
  //定义一个时间类型,用以修改当前时间和日期


  ///


  /// 必需的设计器变量。
  ///

  private System.ComponentModel.Container components = null;


  [ DllImport (  "Kernel32.dll"  )]
  private static extern bool SetSystemTime (  SystemTime time ) ;

  public Form1()
  {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();

   //
   // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   //
  }

  ///


  /// 清理所有正在使用的资源。
  ///

  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

  #region Windows 窗体设计器生成的代码
  ///


  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  ///

  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

  ///


  /// 应用程序的主入口点。
  ///

  [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 ( "不成功!" ,"不成功" ) ;

  }
 }
}

你可能感兴趣的:(使用UDP实现一个时钟服务器)