`
hulunberbus
  • 浏览: 857540 次
文章分类
社区版块
存档分类
最新评论

使用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{
/// <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 ( "不成功!" ,"不成功" ) ;

}
}
}

分享到:
评论

相关推荐

    一个ntp授时服务器软件

    1.NTP服务的端口是123,使用的是udp协议,所以NTP服务器的防火墙必须对外开放udp 123这个端口。 2.Ntpd启动的时候通常需要一段时间进行时间同步,所以在ntpd刚刚启动的时候还不能正常提供时钟服务,最长大概有5分钟吧...

    UDP_arduino_comm:[DEV]通过UDP(ESP8266)进行MPU6050加速读取-包括带有自定义字体的NTP时钟和I2C显示,使用matplotlib滚动显示

    使用的平台: 服务器:带有i2c 0.96英寸图形显示屏和i2c连接的MPU6050的NodeMCU 0.9 ESP8266板该显示屏用于显示服务器的状态:IP地址,连接的客户端的IP地址,MPU6050的状态和数据还有一个NTP同步时钟,用于显示...

    java源码包3

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    distsys-lamport:Lamport 时钟实现,分布式系统项目,2015 年Spring

    它使用简单的 UDP 服务器和客户端进行节点之间的通信。 除了这个 README.md 文件之外,该项目还包含以下文件: lamport.js – 在配置中指定的每个 Ukko 节点上运行的主要 Node.js 文件。 startup.sh – 一个 bash...

    利用RFC868协议编写网络对时程序

    网络授时服务是在网络上设置一些时间服务器,用户通过Internet访问这些时间服务器就可同步本地计算机时钟的服务。网络授时服务有三个协议,分别是Network Time Protocol (RFC-1305),Daytime Protocol (RFC-867),...

    java源码包---java 源码 大量 实例

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    vc++ 应用源码包_1

    一个简单的数字时钟程序,其中的date类派生于MFC CStatic 基类。 CIVStringSet_Demo.zip CIVStringSet_Source.zip 基于MFC和STL平台的字符串类,可以实现在快速字符串搜索。 enum_display_modes_demo.zip enum_...

    vc++ 应用源码包_2

    一个简单的数字时钟程序,其中的date类派生于MFC CStatic 基类。 CIVStringSet_Demo.zip CIVStringSet_Source.zip 基于MFC和STL平台的字符串类,可以实现在快速字符串搜索。 enum_display_modes_demo.zip enum_...

    vc++ 应用源码包_6

    一个简单的数字时钟程序,其中的date类派生于MFC CStatic 基类。 CIVStringSet_Demo.zip CIVStringSet_Source.zip 基于MFC和STL平台的字符串类,可以实现在快速字符串搜索。 enum_display_modes_demo.zip enum_...

    vc++ 应用源码包_5

    一个简单的数字时钟程序,其中的date类派生于MFC CStatic 基类。 CIVStringSet_Demo.zip CIVStringSet_Source.zip 基于MFC和STL平台的字符串类,可以实现在快速字符串搜索。 enum_display_modes_demo.zip enum_...

    vc++ 应用源码包_3

    一个简单的数字时钟程序,其中的date类派生于MFC CStatic 基类。 CIVStringSet_Demo.zip CIVStringSet_Source.zip 基于MFC和STL平台的字符串类,可以实现在快速字符串搜索。 enum_display_modes_demo.zip enum_...

    软件开发报告

    用VC编写一个客户端和服务器端(采用TCP,或UDP协议,具体的实现协议自定),具有以下的系统维护功能: (1)客户端输入命令"ShowAllProcess" 列出服务器所在计算机上的所有运行的进程名和进程号,将这些信息返回给客户端...

    java源码包2

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包4

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    JAVA上百实例源码以及开源项目

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    JAVA上百实例源码以及开源项目源代码

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    vc++ 开发实例源码包

    电子钟的实现,自绘Button、Static的实现,其中自定了一个辅助主题风格类。 CctryLog(web拦截网页帐号密码) 实现了一个控件去获得IHTMLDocument2接口,然后读取内容,匹配用户名与密码等。 CFile64_src 操作大...

    java jdk实列宝典 光盘源代码

    java为数据结构中的列表定义了一个接口类java.util.list同时提供了3个实现类,分别是ArrayList、Vector、LinkedList使用; 生成不重复的随机数序列;列表、集合与数组的互相转换;java为数据结构中的映射定义一个接口...

    最新C++网络编程实践视频教程 陈硕

    第一个Netcat的实现.mkv21.IO-multiplexing方式实现Netcat.mkv22.使用非阻塞IO 1.mkv23.使用非阻塞IO 2.mkv24.进程监控概述.mkv25.实现前要考虑的问题.mkv26.procmon代码解析.mkv27.dummyload实现原理和代码解析.mkv...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Tcp服务端与客户端的JAVA实例源代码 2个目标文件 摘要:Java源码,文件操作,TCP,服务器 Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多...

Global site tag (gtag.js) - Google Analytics