网络同步校时客户端代码(RFC868/C++/WIN32/SOCKET)

原创 2004年11月02日 18:23:00

大量的工业机肯定需要同步校时, 故去察看了RFC868, 我就试编了一个获得网络时间的小程序, 大家可以借鉴到自己的同步校时程序, 只是试验,所以程序结构并不严谨, 过一段时间我会把服务器段的代码贴出,今天先发布客户端:

#pragma warning(disable: 4530)
#pragma warning(disable: 4786)

#include <iostream>
#include <ctime>
#include <cassert>
using namespace std;
#include <winsock2.h>
#include <windows.h>

static char * get_error_msg()
{
 static char msg_buf[1024];
 FormatMessage(
  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  NULL,
  GetLastError(),
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  msg_buf,
  1023,
  NULL
  );
 return msg_buf;
}

void time_internet_to_local(void *recv_buf) //接到的数据转换为本地时间
{
 assert(recv_buf);
 char p[4], *precv = ((char *)recv_buf) + 3;
 for(int i=0; i<4; i++)
  p[i] = *precv--; //网络主机的数据进行转换
 *(long *)p -= 2208988800;//转换为本地时间 time_t

 SYSTEMTIME st;
 tm * ptm = gmtime((time_t *)p);
 st.wYear =  ptm->tm_year + 1900;
 st.wMonth = ptm->tm_mon + 1;
 st.wDay = ptm->tm_mday;
 st.wHour = ptm->tm_hour;
 st.wMinute = ptm->tm_min;
 st.wSecond = ptm->tm_sec;
 st.wMilliseconds = 0;
 SetSystemTime(&st);
}

void print_time(void *recv_buf)//打印接到的数据
{
 assert(recv_buf);
 char p[4], *precv = ((char *)recv_buf) + 3;
 for(int i=0; i<4; i++) //网络主机的数据进行转换
  p[i] = *precv--;
 *(long *)p -= 2208988800;
 char buf[20];
 strftime(buf, 20, "%Y-%m-%d %H:%M:%S", localtime((time_t *)p));
 cout << buf << endl;
}

void tcp(void *ip)//RFC868 PORT 37 TCP协议
{
 struct sockaddr_in server;
 server.sin_family = AF_INET;
 server.sin_port = htons(37);
 server.sin_addr.s_addr = inet_addr((char *)ip) ;

 SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
 if(s == INVALID_SOCKET)
  cout << __LINE__<<"  socket error  : " << WSAGetLastError() << endl;

 int ret = connect(s, (struct sockaddr*)&server, sizeof(server));
 if(ret == SOCKET_ERROR)
  cout << __LINE__ << get_error_msg() << endl;
 else
 {
  char xx[4];
  ret = recv(s, xx, 4, 0);
  if(ret == SOCKET_ERROR) 
   cout << __LINE__ << get_error_msg() << endl;
  else
  {
   print_time(xx);
   //time_internet_to_local(xx);设定本地时间 最好加一个判断网络延时
  }

  if(shutdown(s, SD_RECEIVE) == SOCKET_ERROR)
   cout << __LINE__ << get_error_msg() << endl;
 }
 closesocket(s);
}

void udp(void *ip) //RFC868 PORT 37 UDP
{
 struct sockaddr_in server;
 server.sin_family = AF_INET;
 server.sin_port = htons(37);
 server.sin_addr.s_addr = inet_addr((char *)ip) ;
 
 SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
 if(s == INVALID_SOCKET)
 {
  cout << __LINE__ << get_error_msg() << endl;
 }

 int ret, c_len = sizeof(server);
 char r_buf[4];
 ret = sendto(s, r_buf, 0, 0, (struct sockaddr *)&server, sizeof(server));//发送空的数据报
 if(ret == SOCKET_ERROR)
  cout << __LINE__ << get_error_msg() << endl;

 FD_SET read_set;
 timeval tv = {3, 0}; //tv.tv_sec = 0, tv.tv_usec = 100000; 0.1s
 FD_ZERO(&read_set);
 FD_SET(s, &read_set);
 ret = select(0, &read_set, NULL, NULL, &tv);
 if(ret == SOCKET_ERROR)
 {
  cout << __LINE__ << get_error_msg() << endl;
 }
 else
  if(FD_ISSET(s, &read_set))
  {
   ret = recvfrom(s, r_buf, 4, 0, (struct sockaddr *)&server, &c_len);
   
   if(ret == SOCKET_ERROR)
    cout << __LINE__ << get_error_msg() << endl;
   else
   {
    print_time(r_buf);
   }
  }
 closesocket(s);
}

int main(int argc, char *argv[])
{
 WORD wVersionRequested;
 WSADATA wsaData;
 wVersionRequested = MAKEWORD(2, 2);
 WSAStartup(wVersionRequested, &wsaData);

 char *ipcn = "159.226.154.16";//国家授时中心
 char *iphk = "210.0.235.14";//香港天文台授时中心

 time_t now;
 char buf[20] = {0};

 now = time(NULL);
 strftime(buf, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
 cout << "TCP 连接国家授时中心 " << endl << "本地时间 " << buf << endl << "远程时间 ";
 tcp(ipcn);

 now = time(NULL);
 strftime(buf, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
 cout << "UDP 连接香港天文台授时中心 " << endl << "本地时间 " << buf << endl << "远程时间 ";
 udp(iphk);

 WSACleanup();
 return 0;
}

RFC 868   

Network Working Group                                    J. Postel - ISI
Request for Comments: 868                           K. Harrenstien - SRI
                                                                May 1983

                             Time Protocol

This RFC specifies a standard for the ARPA Internet community.  Hosts on
the ARPA Internet that choose to implement a Time Protocol are expected
to adopt and implement this standard.

This protocol provides a site-independent, machine readable date and
time.  The Time service sends back to the originating source the time in
seconds since midnight on January first 1900.

One motivation arises from the fact that not all systems have a
date/time clock, and all are subject to occasional human or machine
error.  The use of time-servers makes it possible to quickly confirm or
correct a system's idea of the time, by making a brief poll of several
independent sites on the network.

This protocol may be used either above the Transmission Control Protocol
(TCP) or above the User Datagram Protocol (UDP).

When used via TCP the time service works as follows:

   S: Listen on port 37 (45 octal).

   U: Connect to port 37.

   S: Send the time as a 32 bit binary number.

   U: Receive the time.

   U: Close the connection.

   S: Close the connection.

   The server listens for a connection on port 37.  When the connection
   is established, the server returns a 32-bit time value and closes the
   connection.  If the server is unable to determine the time at its
   site, it should either refuse the connection or close it without
   sending anything.

RFC 868                                                         May 1983
Time Protocol                                                          

When used via UDP the time service works as follows:

   S: Listen on port 37 (45 octal).

   U: Send an empty datagram to port 37.

   S: Receive the empty datagram.

   S: Send a datagram containing the time as a 32 bit binary number.

   U: Receive the time datagram.

   The server listens for a datagram on port 37.  When a datagram
   arrives, the server returns a datagram containing the 32-bit time
   value.  If the server is unable to determine the time at its site, it
   should discard the arriving datagram and make no reply.

The Time

The time is the number of seconds since 00:00 (midnight) 1 January 1900
GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this
base will serve until the year 2036.

For example:

   the time  2,208,988,800 corresponds to 00:00  1 Jan 1970 GMT,

             2,398,291,200 corresponds to 00:00  1 Jan 1976 GMT,

             2,524,521,600 corresponds to 00:00  1 Jan 1980 GMT,

             2,629,584,000 corresponds to 00:00  1 May 1983 GMT,

        and -1,297,728,000 corresponds to 00:00 17 Nov 1858 GMT.


RFC868--时间协议客户机与服务器的实现

 本例根据RFC 868网络时间协议分别建立了时间协议的客户机和服务器。1.TimeProtocolConstants类提供提供两个常量静态值:TCP_PORT指定协议的标准TCP端口;EPOCH_O...
  • doncai
  • doncai
  • 2007年08月26日 14:24
  • 2569

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

利用RFC868协议编写网络对时程序 作者:四川绵阳电业局 缪元虎 下载源代码 一、网络授时服务   网络授时服务是在网络上设置一些时间服务器,用户通过Internet访...
  • cosmoslife
  • cosmoslife
  • 2012年05月13日 20:18
  • 461

网络同步校时UDP服务器端SDK代码(RFC868/C++/WIN32/SOCKET/UDP)

#pragma warning(disable: 4530)#pragma warning(disable: 4786)#include #include #include #include #inc...
  • wujian53
  • wujian53
  • 2004年11月04日 18:45
  • 1982

网络同步校时TCP服务器端SDK代码(RFC868/C++/WIN32/SOCKET/TCP/select)

//以下是一段服务器端SDK代码, 较简单, 稍加修改可应用于NT服务程序中//仅供初学者参考, 高手勿入, 谢谢#pragma warning(disable: 4530)#pragma warni...
  • wujian53
  • wujian53
  • 2004年11月03日 19:38
  • 1949

Windows下C++服务端和客户端Socket通信简单代码

// Server.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include...
  • yuan3683084
  • yuan3683084
  • 2014年07月23日 18:48
  • 2675

C++ socket编程基础三(Windows异步套接字)

异步套接字: 如果使用阻塞的套接字的话,在控制台下还好!如果是WIN32程序的话,那么就容易造成界面的假死,因为接收函数一直等待有消息进来之后才会被返回!所以此时界面一直属于假死的状态,如果你乱动的...
  • zh13544539220
  • zh13544539220
  • 2015年04月03日 10:48
  • 3432

C++ 简单的 Tcp 实现[socket] 客户端与客户端通信

开发环境  Vs 2008  新建一个 win32 console  project  //  服务器端代码// Server.cpp : Defines the entry point for th...
  • id19870510
  • id19870510
  • 2010年07月11日 23:53
  • 11740

socket编程之select()-win32下

Select在Socket编程中还是比较重要的,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。    Select的函数格式(Unix系统下的伯克利socket编程,和windows...
  • lzyzuixin
  • lzyzuixin
  • 2011年11月08日 16:26
  • 5084

win32 socket的一个简单的例子

在visual c++里建两个win32控制台工程,分别编译下面的服务端和客户端 服务端: #include #include #include #pragma comment(lib,"w...
  • qq506124204
  • qq506124204
  • 2012年04月27日 01:03
  • 5823

win32 socket编程 示例(功能简单,完善)

最近在做的一个项目要用到网络通信方面的内容,于是自学了下win32socket,原来自己学过计算机网络,只了解网络各层的原理,但没有真正的编程来实现这些原理,哎,不过现在还来得及,下面是自己的一个示例...
  • foreverhuylee
  • foreverhuylee
  • 2014年03月19日 17:41
  • 7772
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:网络同步校时客户端代码(RFC868/C++/WIN32/SOCKET)
举报原因:
原因补充:

(最多只允许输入30个字)