




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
PAGE1网络时间同步系统的设计与实现目录TOC\o"1-5"\h\u161摘要 115623Abstract 16921绪论 2210381.1研究背景 3307651.2主要工作和方法 3309411.3本文结构 3202102相关知识 4296212.1网络时间同步技术相关知识介绍 4169222.1.1网络时间同步概念 4194092.1.2常用的时间同步协议 438822.1.3网络时间同步系统实现原理 597492.1.4C/S系统模型的特点以及TCP三次握手 5304962.1.5VisualC++开发环境及相关知识 6226653系统设计 7135383.1需求分析 7254863.2系统模型设计 7317613.3系统工作流程设计 8137944系统实现 9275404.1服务器端详细设计 965314.2服务器端主要功能的设计与实现 9310604.2.1服务器端通信的连接与建立 9227734.2.2所需时间的获取及发送 10186894.2.3最小化程序到系统托盘的实现 11264934.3客户方详细设计 13117394.3.1客户方通信连接的建立 13277124.3.2时间的接收与同步 14224734.3.3最小化系统托盘的实现 17203394.3.4定时器的设计与实现 19282445系统测试与数据分析 2087055.1检测的方法 20123455.1.1服务器端的测试 20151775.1.2客户方的测试 2193805.1.3系统时间同步的测试 2115075.2数据分析 224964结束语 2231638参考文献 2325489致谢 24
网络时间同步系统的设计与实现摘要:如果网络中主机的时间与服务器的时间不同,就会不便于网络的运行与管理。因此本毕业设计针对这一问题进行了分析,并设计了C/S结构的网络时间同步系统。在这个系统中,客户方首先向服务器发送连接请求,在连接建立以后向服务器请求时间同步,服务器接受请求并将时间发送给客户方,客户方接收后用服务器的时间来同步自己的时间,这样使得网络中主机的时间与服务器的时间一致。关键词:网络时间同步;客户机/服务器;Winsock;设计与实现DesignandImplementationofTimeSynchronismAbstract:Ifthehostandtheserveraredifferentatnetworktime,it'snotconvenientfortheadministratortomanagementthenetwork,sothearticleanalysisthematteranddesignsthesystemoftimesynchronism.Inthissystem,theclientsendstherequesttoconnecttheservertoalterthetime.Theserverlistensandreplystherequest,inthiswaytheclientandtheserverwillhavethesametimeinthenetwork.KeyWords:NetworkTime;Client/Server;Winsock;DesignandImplementation
1绪论1.1研究背景随着计算机网络技术及其应用的深入发展,当今社会计算机在人们的生活和工作中发挥着越来越重要的作用,网络时间同步技术显得越来越为重要。如何精确的同步网络中主机的时间,经历了长足的发展,从七十年代末八十年代初,网络时间同步技术的初步发展,到各种网络时间同步协议的诞生,网络时间同步技术经历了萌芽、快速发展、基本成熟、继续发展等阶段,时间同步精度与稳定性也越来越高,并且得到了相当广泛的应用[1]。网络时间同步技术广泛的应用在Internet上的计算机,计算机时钟用于记录事件的时间信息,如E-MAIL信息、文件创建和访问时间、数据库处理时间等。时钟还被用于控制备份的操作、为设计自动构造编译器检查文件是否变动过以及其他应用,在同步设备系统、光传输设备系统、3G基站设备系统这些需要精确时间的系统中,网络时间同步系统就显得尤为重要[2]。随着计算机网络技术及其应用的深入发展,人们开始在计算机构成的虚拟空间开展活动。许多重要领域必须依靠计算机系统的高可靠性和高效率来精确控制关键的工作与任务,尤其在分布式系统中需要在大范围内保持网络中计算机间的时间同步和时间的准确性,然而现实中计算机的时钟工作并不太稳定,容易受到温度、电源等环境条件的影响[3],在这些条件的影响下,要精确的同步网络中的所有主机的时间,是一件很有必要的事情,这些都推动了网络时间同步技术的研究。1.2主要工作和方法查找参考资料,了解有关的VC++网络编程知识以及MFC的运用,系统主要采用VC++语言通过Winsock编程来设计与实现网络中主机与服务器之间的时间同步问题,网络时间同步系统主要分为两个部分:服务器端程序和客户端程序。在设计服务器程序时候,采用TCP报文传输,因为TCP是面向连接的传输方式,是一种可靠的传输方式,服务器根据客户端的请求建立虚连接,并且响应客户端的请求,利用GetLocalTime函数得到系统的时间,服务器监听到客户方请求的时间以及服务器响应客户方的时间封装在报文中,通过Send函数将存放这些时间的数组Sbuff发送到客户方中,客户方请求时间同步后,利用receive函数接收服务器发送来的数组,通过strncpy函数取出数组中的时间,并且结合自己的时间算出报文在网络中的传输时间,最后同步自己的时间,此外客户端以及服务器还增加了最小化程序到系统托盘的功能,便于程序在后台运行。为了能够定期的实现客户方与服务器的时间同步功能,在系统中增加了定时器,可以定期的对客户方进行时间同步,不需要每次都手动的同步客户方与服务器的时间。1.3本文结构本文第1部分绪论主要说明了本文的研究背景、主要工作和实现方法。第2部分相关知识介绍了网络时间同步的定义、常用的协议、系统组成,以及VC++开发环境及相关知识。第3部分系统设计,阐述了需求分析、系统模型设计和系统工作流程设计。第4部分系统实现给出系统各个功能模块的详细设计与主要代码的实现。第5部分系统测试与数据分析,说明了检测目标和方法以及检测结果。2相关知识2.1网络时间同步技术相关知识介绍2.1.1网络时间同步概念网络时间同步是指将计算机或设备的时间与网络上的时间源保持一致[3],时间源是网络中提供可靠时间的设备,其标准是时间的精准可靠,使用互联网同步个人计算机的时间是十分方便的,目前国内外都免费提供这种服务。国际上有几百台一级时间服务器提供这种时间同步服务,其中以美国国家标准技术研究院(NIST)的性能最好[4]。2.1.2常用的时间同步协议在时间同步技术中常用的协议主要有:时间协议(TimeProtocol)、日时协议(DaytimeProtocol)和网络时间协议(NetworkTimeProtocol,NTP)[5]。时间协议(TimeProtocol)[6]:该协议提供了一个独立于站点的,机器可读的日期和时间信息。时间服务返回的是以秒数,是从1990年1月1日午夜到现在的秒数。设计这个协议的一个重要目的在于,网络上的许多主机并没有时间的观念,在分布式的系统上,主机的时间往往可以人为改变,而且因为机器时钟内的误差而变得不一致,因此需要使用时间服务器通过选举方式得到网络时间,让服务器有一个准确的时间观念。日时协议(DaytimeProtocol)[7]:该协议是本RFC规范了一个ARPAInternetcommunity上的标准。在ARPAInternet上的所有主机应当采用和实现这个标准。一个有用的测量和调试工具就是daytime服务。它的作用就是返回当前时间和日期,格式是字符串格式。这种时间传输协议广泛的被运行MS-DOS和类似的操作系统的小型计算机使用,该协议不指定固定的传输格式,只要求按照ASCII标准发送数据。最普且最繁杂的是网络时间协议(NetworkTimeProtocol,NTP),该协议是美国德拉瓦大学的Mills教授于1985年提出的,已经发展了20多年,可以兼容Unix,VMS和Windows等多种操作系统,网络时间协议(NTP)的首次实现记载在InternetEngineeringNote之中,其精确度为数百毫秒。稍后出现了首个时间协议的规范,即RFC-778,它被命名为DCNET互联网时间服务,而它提供这种服务还是借助于InternetcontrolMessageProtocol(ICMP),即互联网控制消息协议中的时间戳和时间戳应答消息作为NTP[8]。名称的首次出现是在RFC-958之中,该版本也被称为NTPv0,其目的是为ARPA网提供时间同步。它己完全脱离ICMP,是作为独立的协议以完成更高要求的时间其时间同步精度在局域网上可以达到毫秒级,在全球互联网上也可以达到几十毫秒。NTP提供准确时间,首先要有准确的时间来源,这一时间应该是国际标准时间UTC。NTP获得UTC的时间来源可以是原子钟、天文台、卫星,也可以从Internet上获取。这样就有了准确而可靠的时间源。时间按NTP服务器的等级传播。按照离外部UTC源的远近将所有服务器归入不同的Stratun(层)中。Stratum-1在顶层,有外部UTC接入,而Stratum-2则从Stratum-1获取时间,Stratum-3从Stratum-2获取时间,以此类推,但Stratum层的总数限制在15以内。所有这些服务器在逻辑上形成阶梯式的架构相互连接,而Stratum-1的时间服务器是整个系统的基础[9]。计算机主机一般同多个时间服务器连接,利用统计学的算法过滤来自不同服务器的时间,以选择最佳的路径和来源来校正主机时间。即使主机在长时间无法与某一时间服务器相联系的情况下,NTP服务依然有效运转。2.1.3网络时间同步系统实现原理在本毕业设计中客户方通过向服务器端发送时间同步请求获取服务器方的时间来同步自己的时间,然而由于在网络中数据包的传输需要通过物理介质,以及数据包在网络上传输的距离长短等因素,因此在报文的传输过程中会产生网络延迟,所以当客户方从服务器端获取服务器的时间时,其由于报文传输过程中所产生的网络延迟,所以此时获取的时间不是服务器当前的时间,而此时服务器的时间等于客户方获取的时间加上网络延迟的时间之和,所以网络时间同步原理如图2-1所示,其中:T1:客户方发送方查询请求时间(以客户方时间系统为参照);T2:服务器受到查询请求时间(以服务器时间系统为参照);T3:服务器回复时间信息包时间(以服务器时间系统为参照);T4:客户方受到回复时间信息包的时间(以客户方时间系统为参照);δ1:请求信息在网上传播消耗的时间;δ2:回复信息在网上传播消耗的时间;假设请求信息在网上传播消耗的时间δ1与回复信息在网上传播的时间δ2相等,因此数据包在网络传输过程中产生的网络延迟为T=1/2[(T2-T1)+(T4-T3)]。所以客户方需要同步的时间为服务器的时间加上网络延迟,即:客户方时间Ctime=Stime+T图2-1时间同步原理图2.1.4C/S系统模型的特点以及TCP三次握手网络时间同步系统采用C/S(客户/服务器)模式,主要有两部分组成:服务器与客户端。采用C/S模式主要是有以下优点:C/S模式将应用与服务分离,系统具有稳定性和灵活性C/S模式配备的是点对点的结构模式,适用于局域网,有可靠的安全由于客户端实现与服务器端的直接连接,没有中间环节,因此响应速度快在C/S模式中,作为客户机的计算机都要安装客户机程序,只需要一台服务器就可以管理整个网络。网络中客户端与服务器端的连接采用TCP连接方式,即所谓的“三次握手”[10](图2-1):(1)第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;(2)第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;(3)第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。图2-1TCP三次握手2.1.5VisualC++开发环境及相关知识VisualC++是Windows平台上的C++编程环境,学习VC要了解很多Windows平台的特性并且还要掌握MFC、ATL、COM等知识。MFC是Win32API的包装类,需要理解文档视图类的结构,窗口类的结构,消息流向等等;COM是代码共享的二进制标准,需要掌握其基本原理等等。VC++应用程序的开发主要有两种模式,一种是WINAPI方式,另一种则是MFC方式,传统的WINAPI开发方式比较繁琐,而MFC则是对WINAPI再次封装,所以MFC相对于WINAPI开发更具备效率优势,MFC的英文全称是MicrosoftFundationClasses,即微软的基本类库,MFC的本质就是一个包含了许多微软公司已经定义好的对象的类库,虽然要编写的程序在功能上是千差万别的,但从本质上来讲,都可以化归为用户界面的设计、对文件的操作、多媒体的使用、数据库的访问等等一些最主要的方面[11]。这一点正是微软提供MFC类库最重要的原因,在这个类库中包含了一百多个程序开发过程中最常用到的对象。在进行程序设计的时候,如果类库中的某个对象能完成所需要的功能,只要简单地调用已有对象的方法就可以了。还可以利用面向对象技术中很重要的“继承”方法从类库中的已有对象派生出我们自己的对象,这时派生出来的对象除了具有类库中的对象的特性和功能之外,还可以自己根据需要加上所需的特性和方法,产生一个更专门的,功能更为强大的对象。当然,也可以在程序中创建全新的对象,并根据需要不断完善对象的功能。相比较而言,WINAPI方式更加的本质与复杂,MFC则相对的简单与抽象,而且MFC本身就是对WINAPI再次封装,所以MFC相对于WINAPI开发更具备效率优势,MFC的功能在正常情况下可以满足绝大部分的需要,必要时可以直接调用API函数,但是反过来却十分困难,而且MFC与VC++融合拥有很多人性化的特性,比如界面、通用对话框等等,所以在设计这个系统的时候我采用MFC方式。总之VisualC++是一个功能强大且非常实用的编程工具。3系统设计3.1需求分析为使客户方与服务器方的时间能够同步,系统设计成客户/服务器模式(C/S模式),C/S模式是一种两层结构的系统,第一层在客户机上安装了客户机应用程序,第二层在服务器上安装服务器管理程序。在C/S模式的工作过程中,客户方要能够向服务器方请求时间同步,即可以与服务器在一个网络中相互通信,并且要能够接收从服务器发送来的应答,提取服务器的时间并同步自己的时间,而服务器要能够监听、响应客户方的同步请求,将自己的时间封装在报文中发送给客户方。为了方便客户方能够定时的与服务器同步时间,在本系统中增加了定时器的功能,定时器主要的功能是在设定的时间内使客户方主动的同步服务器的时间,避免了手动同步带来的不便。系统应能长期自动运行,为使桌面简洁,程序应增加可最小化到托盘区的功能。3.2系统模型设计在这个C/S模式结构中服务器功能模块的主要作用是:(1)打开一个套接字socket(2)将套接字绑定到服务器的地址上(3)等待连接请求,做好接收连接请求的准备(4)监听连接请求(5)如果连接请求到、则建立连接,连接建立后将服务器的时间发送给客户端(6)数据交换完成后,关闭套接字客户端功能模块的主要作用:(1)打开一个套接字(2)发起连接请求(3)如果连接成功,向服务器发送同步时间的请求(4)根据服务器的时间同步自己的时间,并显示出来(5)数据交换完成,关闭套接字3.3系统工作流程设计系统中客户方与服务器从建立连接、发送同步请求到同步系统时间的流程如图3-1所示:在整个时间同步过程中服务器必须要处于工作状态,时刻监听着网络中客户方的请求信息,监听到客户方的时间同步请求时,根据客户方的需要,来进行服务响应,客户方在接收到服务器的响应报文后,根据算服务器发送过来的时间,以及算出的网络延时来同步系统的时间。图3-1系统流程图4系统实现4.1服务器端详细设计服务器在整个系统中占有很重要的地位,负责建立套接字,绑定本地端口并监听应客户方发送的时间同步请求,最后对该请求进行响应,在建立套接字时主要用到SOCKET函数,原型为SOCKETsocket(intaf,,inttype,intprotocol);该函数的主要作用是创建一个能够进行网络通信的套接字;对该端口进行绑定用到bind()函数,该函数的作用是通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号),对于客户端的请求监听用函数listen(),原型为intlisten(SOCKETs,intbacklog);其作用是在套接字函数中表示让一个套接字处于监听到来的连接请求的状态,最后对客户方的请求进行响应,用Send()函数来实现,该函数的功能是向窗口发送指定的消息并立即执行相应的事件处理程序。在本系统中服务器要向客户方发送三个时间,分别是:客户方在请求时间同步时候客户方的时间T1,服务器在服务器在接收到客户方请求时间同步时的时间T2,以及服务器响应客户方时间同步请求的时间T3。服务器在得到这三个时间之后,会将它们按照顺序存放在字符数组SSS中,然后发送给客户方。4.2服务器端主要功能的设计与实现4.2.1服务器端通信的连接与建立要想在网络中与客户方进行通信,首先必须通过SOCKET函数建立服务器端的通信SOCKET,有三种Socket,原始Socket(SOCK_RAW)、数据流Socket(SOCK_STREAM)、数据报Socket(SOCK_DGRAM),在本系统中,传输需要可靠的连接方式,因此采用数据流Socket连接方式:sockaddr_insaClient; SOCKETsockTemp=NULL;ASSERT(g_hSocket!=NULL); intnLengthAddr=sizeof(SOCKADDR);if((g_hSocket=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) { AfxMessageBox("创建Socket失败"); return; }通信必须要有地址,这时候就用到IP,接下来设置服务器端绑定的地址结构,采用INET协议族地址结构sockaddr_in:sockaddr_insaServer; saServer.sin_family=AF_INET; saServer.sin_port=htons(CONNECE_PORT);//saServer.sin_addr.s_addr=htons(INADDR_ANY); saServer.sin_addr.s_addr=inet_addr("99");其中saServer.sin_family=AF_INET;表示该协议族支持多个地址族,saServer.sin_port=htons(CONNECE_PORT);表示采用本地的常用端口进行通信,saServer.sin_addr.s_addr=inet_addr("99");表示设定服务器的地址为99,即服务器所在计算机的地址。设定完服务器的地址以后就要对其进行绑定,利用bind函数,方法如下://绑定地址 if(bind(g_hSocket,(sockaddr*)&saServer,sizeof(SOCKADDR))==SOCKET_ERROR) { AfxMessageBox("绑定地址失败"); return; }绑定完成后,服务器就可以对网络中的客户方进行时间同步请求监听:if(listen(g_hSocket,5)==SOCKET_ERROR) { AfxMessageBox("监听客户端请求失败"); return; } //启动一线程来处理客户端请求 AfxBeginThread(ServerThreadProc,0); //使开始按钮变灰 GetDlgItem(IDC_START)->EnableWindow(FALSE); }当服务器Listen函数监听到客户方的时间同步请求时,服务器调用线程处理客户方的请求,并且使“开始”按钮变灰,处理客户方的请求。4.2.2所需时间的获取及发送当服务器在接收到客户方的时间请求信息包时,会将其中包含的时间T1分解出来charSSS[1000]="SetTime";strcat(SSS,sCommand+8);//得到客户方发送连接请求的时间t1其中字符数组SSS是用来存放客户方所需要的三个时间的,"SetTime"是用来通知客户方同步本地时间的字符串,sCommand是存放客户方发送过来的时间同步请求的信息,里面封装着客户方在发送同步请求时的系统时间T1,sCommand+8表示从数组的第八位开始存放的是时间T1。并将获取的时间T1放入数组SSS中。服务器监听到客户方的请求前利用GetLocalTime函数得到服务器的时间即T2,并将获得的时间放入字符数组sBuff中:SYSTEMTIMEt2; charsBuff[256]; GetLocalTime(&t2); sprintf(sBuff,"%4d%2d%2d%2d%2d%2d", t2.wYear,t2.wMonth,t2.wDay,t2.wHour,t2.wMinute,t2.wSecond);strcat(SSS,sBuff); 其中t2.wYear,t2.wMonth,t2.wDay,tit2.wHour,t2.wMinute,t2.wSecond依次为服务器当前时间的年、月、日、时、分秒再获取这些时间后将时间T2依次放在T1的后面存入数组SSS中。同理可得到时间T3,然后用strcat(SSS,sBuff);将时间T3放在T2的后面存入数组SSS。在服务器得到这三个时间以后便通过send函数将其发送给客户方具体代码如下:intnBytesSent; if((nBytesSent=send(sockTemp,SSS,strlen(SSS),0))==SOCKET_ERROR) { AfxMessageBox("发送数据失败"); return1; } }当服务器对客户方的的时间同步请求响应完成以后,服务器在最后通信结束时会将之前建立好的套接字关闭,结束通信: //关闭Socket if(closesocket(sockTemp)==SOCKET_ERROR) { AfxMessageBox("关闭连接失败"); sockTemp=NULL; return1; } return0;}4.2.3最小化程序到系统托盘的实现此外在服务器中增加了最小化系统托盘的作用即在运行服务器方或者客户方的程序时,会在任务栏的最右方出现相关的图标,表示程序正在运行之中,当要退出程序的时候,可以右键点击图标,此时会“退出”按钮,左键单击“退出”既可以退出程序。基本步骤如下:(1)添加消息响应函数OnInitDialog(),这样程序一启动,就在托盘中显示出了自己应用程序的图标。主要代码为://托盘显示//m_nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);m_nid.hWnd=this->m_hWnd;m_nid.uID=IDR_MAINFRAME;m_nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;m_nid.uCallbackMessage=WM_SHOWTASK;//自定义的消息名称m_nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));strcpy(m_nid.szTip,"服务器程序");//信息提示条为"服务器程序"Shell_NotifyIcon(NIM_ADD,&m_nid);//在托盘区添加图标在Dialog源文件中添加自定义的消息响应代码,代码作用是:当左键双击时在桌面上弹出应用程序主窗口,右键单击弹出关闭菜单,程序代码如下:LRESULTCServerDlg::OnShowTask(WPARAMwParam,LPARAMlParam){if(wParam!=IDR_MAINFRAME)return1;switch(lParam){caseWM_RBUTTONUP://右键单击时弹出菜单{LPPOINTlpoint=newtagPOINT;::GetCursorPos(lpoint);//得到鼠标位置CMenumenu;menu.CreatePopupMenu();//声明一个弹出式菜单menu.AppendMenu(MF_STRING,WM_DESTROY,"关闭");menu.TrackPopupMenu(TPM_LEFTALIGN,lpoint->x,lpoint->y,this);HMENUhmenu=menu.Detach();menu.DestroyMenu();deletelpoint;}break;caseWM_LBUTTONDBLCLK://双击左键的处理{this->ShowWindow(SW_SHOWNORMAL);//显示主窗口}break;}return0;}(3)添加OnSize消息响应函数,当鼠标左键点击对话框最小化图标时,会调用该函数隐藏主窗口:voidCServerDlg::OnSize(UINTnType,intcx,intcy){CDialog::OnSize(nType,cx,cy);//TODO:Addyourmessagehandlercodehereif(nType==SIZE_MINIMIZED){ShowWindow(SW_HIDE);//当最小化时,隐藏主窗口}}(4)添加关闭窗口时的消息响应函数:DestroyWindow(),在图标上单击右键弹出关闭对话框,点击会将托盘中的应用程序图标删除BOOLCServerDlg::DestroyWindow(){//TODO:Addyourspecializedcodehereand/orcallthebaseclass//在托盘区删除图标Shell_NotifyIcon(NIM_DELETE,&m_nid);returnCDialog::DestroyWindow();}4.3客户方详细设计客户方在本系统中向服务器发送时间同步请求,在获得服务器方发送过来的时间包后,从数组中将时间提取出来,然后转化成整形,算出网络延时,利用SetLocalTime函数同步系统的时间。4.3.1客户方通信连接的建立客户方要想和服务器进行通信,发送时间同步请求,客户方首先要能利用服务器的IP地址与服务器进行连接,首先要定义客户方接收服务器IP的Socket地址结构,代码如下://设置客户端要同步的服务器的sockaddr_in结构 Sockaddr_inm_ServerAddr;m_ServerAddr.sin_family=AF_INET;m_ServerAddr.sin_port=htons(CONNECE_PORT);m_ServerAddr.sin_addr.s_addr=inet_addr(strServer); m_hSocket=NULL;在这个结构中定义了,服务器的地址协议族AF_INET、常用连接端口CONNECE_PORT、以及IP地址inet_addr(strServer);定义完要同步的服务器的sockaddr_in结构后,就可以输入服务器的IP地址进行连接//得到服务器IP地址 BYTEb1,b2,b3,b4; m_ctrlServer.GetAddress(b1,b2,b3,b4);charstrServer[256]; memset(strServer,0,256); sprintf(strServer,"%d.%d.%d.%d",b1,b2,b3,b4);其中,m_ctrlServer表示程序界面中输入IP的控件,用来获取所输入的服务器IP。因为IP地址是三十二位的,分为四个字节,每个字节占八位,所以定义了四个字节型变量b1,b2,b3,b4;来接收服务器的IP,完成这些以后就可以连接服务器了,//连接服务器ASSERT(m_hSocket!=NULL); if(connect(m_hSocket,(sockaddr*)&m_ServerAddr,sizeof(SOCKADDR))==SOCKET_ERROR) { AfxMessageBox("连接服务器失败"); return; }4.3.2时间的接收与同步在与服务器建立连接以后,客户方就可以向服务器发送时间同步请求,在发送之前会构造一个消息命令串,该字符串的主要作用是提醒服务器,客户方要进行时间同步,这样服务器在接收到该消息命令串以后就会将时间发送过来。//构造消息命令串,表明客户方要进行时间同步 CStringstrMsg="GetTime";在构造好这个命令消息字符串以后,客户方还需要得到本地的时间(即T1),并添加在请求报文(即strMsg)中,一起发送给服务器来请求需要同步的时间, //向服务器端发送消息请求FD_SETfd={1,m_hSocket}; TIMEVALtv={TIME_OUT,0}; if(select(0,NULL,&fd,NULL,&tv)==0) { AfxMessageBox("发送超时"); return; } intnBytesSent; if((nBytesSent=send(m_hSocket,strMsg,nLen,0))==SOCKET_ERROR) { AfxMessageBox("发送数据失败"); return; }当数据成功发送以后,服务器会将客户方所需要的时间发送过来,此时客户方会利用recv函数进行接收,//收取数据 charm_pReadBuf[256]; //循环等待服务器的相应消息 while(1){ //给接受数据缓冲区清零 memset(m_pReadBuf,0,256); if(select(0,&fd,NULL,NULL,&tv)==0) { AfxMessageBox("接受超时"); return; } //接收数据 intnBytesReceived; if((nBytesReceived=recv(m_hSocket,m_pReadBuf,255,0))==SOCKET_ERROR) { AfxMessageBox("接受数据失败"); return; } //如果接受到的数据长度大于0,则退出循环,否则循环等待 if(nBytesReceived>0) break; };charstrCommand[9]; memset(strCommand,0,9); strncpy(strCommand,m_pReadBuf,8); if(strcmp(strCommand,"SetTime")==0) {inttemp=0; charsYear[5],sMonth[3],sDay[3],sHour[3],sMinute[3],sSecond[3]; memset(sYear,0,5); memset(sMonth,0,3); memset(sDay,0,3); memset(sHour,0,3); memset(sMinute,0,3); memset(sSecond,0,3);}由于在客户方接收的字符数组中存放着三个时间T1、T2、T3,需要按照字符存放的顺序依次提取出这三个时间,上面的代码是用来提取时间T1的,T2、T3的提取与此类似就不再赘述。在这里客户方定义了两个字符数组,一个为m_pReadBuf,用来存储服务器方发送过来的时间,另外一个strCommand,用来定义年、月、日、时、分、秒。在接收到这些时间以后,客户方会利用strncpy函数,来对从服务器发送来的时间进行时间匹配即,将时间与年、月、日、时、分、秒相对应起来,便于客户方设置本机的时间此外,在客户方收到服务器响应的时候会用GetLocalTime函数得到当时的时间T4,以及从服务器方发送过来的T1、T2、T3。这时便可以根据这四个时间来计算数据在网络中传输过程中产生的网络延时,T=[(T2-T1)+(T4-T3)]/2。由于从数据包中得到的时间是字符型的,所以要将其转化成整型的,便于客户方设置自己的时间,//根据服务器发过来的时间数据设置本机时间 SYSTEMTIMEtime; time.wYear=atoi(sYear)+T; time.wMonth=atoi(sMonth)+T; time.wDay=atoi(sDay)+T; time.wHour=atoi(sHour)+T; time.wMinute=atoi(sMinute)+T; time.wSecond=atoi(sSecond)+T; time.wMilliseconds=0;time.wDayOfWeek=0;SetLocalTime(&time);其中atoi的作用便是将字符型转化成整型。SetLocalTime按照客户端系统所设置的时区设置本地系统时间,函数原型是voidSetLocalTime(LPSYSTEMTIMElpSystemTime//addressofsystemtimesstructure);lpSystemTime:指向一个用户自定义包含日期和时间信息的类型为SYSTEMTIME的变量,该变量用来保存函数获取的时间信息[12]。4.3.3最小化系统托盘的实现在客户端程序中也加入了最小化托盘的作用,实现的步骤如下:(1)添加消息响应函数OnInitDialog(),这样程序一启动,就在托盘中显示出了自己应用程序的图标。主要代码为://托盘显示//m_nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);m_nid.hWnd=this->m_hWnd;m_nid.uID=IDR_MAINFRAME;m_nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;m_nid.uCallbackMessage=WM_SHOWTASK;//自定义的消息名称m_nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));strcpy(m_nid.szTip,"客户方程序");//信息提示条为"服务器程序"Shell_NotifyIcon(NIM_ADD,&m_nid);//在托盘区添加图标在Dialog源文件中添加自定义的消息响应代码,代码作用是:当左键双击时在桌面上弹出应用程序主窗口,右键单击弹出关闭菜单,程序代码如下:LRESULTCServerDlg::OnShowTask(WPARAMwParam,LPARAMlParam){if(wParam!=IDR_MAINFRAME)return1;switch(lParam){caseWM_RBUTTONUP://右键起来时弹出菜单{LPPOINTlpoint=newtagPOINT;::GetCursorPos(lpoint);//得到鼠标位置CMenumenu;menu.CreatePopupMenu();//声明一个弹出式菜单menu.AppendMenu(MF_STRING,WM_DESTROY,"关闭");menu.TrackPopupMenu(TPM_LEFTALIGN,lpoint->x,lpoint->y,this);HMENUhmenu=menu.Detach();menu.DestroyMenu();deletelpoint;}break;caseWM_LBUTTONDBLCLK://双击左键的处理{this->ShowWindow(SW_SHOWNORMAL);//显示主窗口}break;}return0;}(3)添加OnSize消息响应函数,当鼠标左键点击对话框最小化图标时,会调用该函数隐藏主窗口:voidCServerDlg::OnSize(UINTnType,intcx,intcy){CDialog::OnSize(nType,cx,cy);//TODO:Addyourmessagehandlercodehereif(nType==SIZE_MINIMIZED){ShowWindow(SW_HIDE);//当最小化市,隐藏主窗口}}(4)添加关闭窗口时的消息响应函数:DestroyWindow(),在图标上单击右键弹出关闭对话框,点击会将托盘中的应用程序图标删除BOOLCServerDlg::DestroyWindow(){//TODO:Addyourspecializedcodehereand/orcallthebaseclass//在托盘区删除图标Shell_NotifyIcon(NIM_DELETE,&m_nid);returnCDialog::DestroyWindow();}4.3.4定时器的设计与实现为使客户端可以定时与服务器端进行时间同步,在客户端中加入了定时器。用函数SetTimer()来生成一个定时器,SetTimer这个API函数的原型为:UINT_PTRSetTimer(HWNDhWnd,UINT_PTRnIDEvent,UINTuElapse,TIMERPROClpTimerFunc);其中HWNDhWnd为窗口句柄,UINT_PTRnIDEvent,为定时器ID,多个定时器时,可以通过该ID判断是哪个定时器,UINTuElapse为时间间隔,单位为毫秒,TIMERPROClpTimerFunc为回调函数[13]。主要代码如下:SetTimer(1,1000,NULL);//启动定时器1CStringstrTime;CTimetm(time.wYear,time.wMonth,time.wDay,time.wHour,time.wMinute,time.wSecond);strTime=tm.Format("%y年%m月%d日%X");//格式化系统时间m_TIME.SetWindowText(strTime);//初始化编辑框的显示 SetTimer(2,1*60*1000,NULL);//启动定时器2{ //TODO:Addyourmessagehandlercodehereand/orcalldefault if(nIDEvent==1) { CStringstrTime; CTimetm; tm=CTime::GetCurrentTime();strTime=tm.Format("%y年%m月%d日%X");//格式化系统时间m_TIME.SetWindowText(strTime);//编辑框动态显示时间 } else//if(nIDEvent==2) { OnSynch(); }CDialog::OnTimer(nIDEvent);}其中SetTimer(1,1000,NULL);为定时器1,这个定时器的主要作用是动态的显示出客户方的当前时间,SetTimer(2,15*60*1000,NULL);为定时器2,主要作用是每隔15分钟,与服务器进行一次时间同步。5系统测试与数据分析5.1检测的方法系统测试是为了发现错误而执行程序的过程,成功的测试是发现了至今尚未发现的错误的测试。测试的目的就是希望能以最少的人力和时间发现潜在的各种错误和缺陷。系统测试是保证系统质量和可靠性的关键步骤,是对系统开发过程中的系统分析系统设计和实施的最后复查。5.1.1
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 停止合作合同范例
- 九年级语文上册第六单元22唐睢不辱使命第2课时教案新版新人教版
- 农业水费征收合同范例
- 2025年燃煤发电机组项目发展计划
- 个人货运服务合同范例
- 保洁终止合同范例
- 串串生菜采购合同范例
- 供货安装服务合同范例
- 借款受托支付合同范例
- 任务价值和尽责性与初中生语文学习投入及成绩的关系研究
- GB/T 45236-2025化工园区危险品运输车辆停车场建设规范
- 2025年安徽交通职业技术学院单招综合素质考试题库一套
- 2025年北京社会管理职业学院单招职业技能考试题库及参考答案一套
- 2025年南京信息职业技术学院单招职业技能测试题库汇编
- 2025春教科版(2024)小学一年级下册科学全册教案
- 2025年哈尔滨幼儿师范高等专科学校单招职业技能测试题库学生专用
- 计算机一级测试题(附参考答案)
- 企业内部系统使用权限规范
- 教学课件-液压与气压传动项目教程(侯守军)
- 2024年亳州职业技术学院单招职业技能测试题库
- 2025年旅行与旅游的未来:拥抱可持续与包容性增长报告(英文版)-世界经济论坛
评论
0/150
提交评论