毕设VC做的一个SNTP协议的客户端类CSNTPClient

资源地址:http://download.csdn.net/source/1511213

//GetLocalTime和SetLocalTime是本机时间

//GetSystemTime和SetSystemTime是零时区时间

 

 

调用方法

CSNTPClient client;

client.RequestServer("210.72.145.44");

 

//SNTPClient.h //------------------------- #pragma once #include "afx.h" #define LI 0 #define VN 3 #define MODE -1 #define STRATUM 0 #define POLL 4 #define PREC -6 #define T4 stReferenceTimestamp #define T1 stOriginateTimestamp #define T2 stReceiveTimestamp #define T3 stTransmitTimestamp #define offReferenceTimestamp 4 #define offOriginateTimestamp 6 #define offReceiveTimestamp 8 #define offTransmitTimestamp 10 #define offT4 4 #define offT1 6 #define offT2 8 #define offT3 10 class CSNTPClient : public CObject { public: CSNTPClient(void); ~CSNTPClient(void); public: BOOL RequestServer(CString strServer,int nPort = 123); private: void InitData(); void AnalyseData(); unsigned __int64 GetTotalMilliseconds(SYSTEMTIME st); SYSTEMTIME ConverToSystemTime(unsigned int offset); BOOL MySetLocalTime(); private: /*SYSTEMTIME stSNTPStart;*/ unsigned __int64 nSNTPStartMilliseconds; unsigned int data[12]; int nTimeOff; //T4 Reference Timestamp SYSTEMTIME stReferenceTimestamp; //COleDateTime otReferenceTimestamp; //T1 Originate Timestamp SYSTEMTIME stOriginateTimestamp; //COleDateTime otOriginateTimestamp; //T2 Receive Timestamp SYSTEMTIME stReceiveTimestamp; //COleDateTime otReceiveTimestamp; //T3 Transmit Timestamp SYSTEMTIME stTransmitTimestamp; //COleDateTime otTransmitTimestamp; }; //SNTPClient.cpp //------------------------- #include "StdAfx.h" #include "SNTPClient.h" #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") /* **------------------------------------------------------------ ** 函数: ** CSNTPClient::CSNTPClient(void) ** ** 参数: ** 无 ** ** 功能: ** ** 构造函数,初始化SNTP协议的时间起点(1900-01-01 00:00:00) ** ** 返回: ** 无 ** **------------------------------------------------------------ */ CSNTPClient::CSNTPClient(void) { SYSTEMTIME st; FILETIME ft; st.wYear = 1900; st.wMonth = 1; st.wDay = 1; st.wHour = 0; st.wMinute = 0; st.wSecond = 0; st.wMilliseconds = 0; //把SYSTEMTIME结构的时间转化为FILETIME结构的时间 SystemTimeToFileTime(&st,&ft); //利用FILETIME结构计算出时间的毫秒数 nSNTPStartMilliseconds = (ft.dwHighDateTime * 0x100000000L + ft.dwLowDateTime) / 10000L; } /* **------------------------------------------------------------ ** 函数: ** CSNTPClient::~CSNTPClient(void) ** ** 参数: ** 无 ** ** 功能: ** ** 析构函数,释放资源 ** ** 返回: ** 无 ** **------------------------------------------------------------ */ CSNTPClient::~CSNTPClient(void) { } /* **------------------------------------------------------------ ** 函数: ** BOOL CSNTPClient::RequestServer(CString strServer,int nPort) ** ** 参数: ** CString strServer 要连接的SNTP的地址 ** int nPort 连接的端口,默认为123 ** ** 功能: ** ** 连接SNTP服务器获取时间 ** ** 返回: ** 成功返回(TRUE),失败返回(FALSE) ** **------------------------------------------------------------ */ BOOL CSNTPClient::RequestServer(CString strServer,int nPort) { WSADATA wsadata; CString strMsg; //初始化 int nRet = WSAStartup(MAKEWORD(2,2),&wsadata); if(nRet != NO_ERROR) { strMsg.Format(_T("Error at WSAStartup Code:%d"),GetLastError()); AfxMessageBox(strMsg,MB_ICONERROR); return FALSE; } SOCKET server; //建立SOCKET server = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if(server == INVALID_SOCKET) { strMsg.Format(_T("Error at socket Code:%d"),WSAGetLastError()); AfxMessageBox(strMsg,MB_ICONERROR); WSACleanup(); return FALSE; } SOCKADDR_IN addrServer; TCHAR chServer[64]; _tcscpy_s(chServer,sizeof(chServer),strServer); addrServer.sin_family = AF_INET; //addrServer.sin_addr.s_addr = inet_addr(chServer); addrServer.sin_port = htons(nPort); struct hostent* hp=NULL; //填充服务器的地址 if(inet_addr(strServer)==INADDR_NONE) { hp=gethostbyname(strServer); if(hp==NULL) { return FALSE; } //addrServer.sin_addr.s_addr=*((unsigned long*)hp->h_addr_list); RtlCopyMemory(&addrServer,hp->h_addr_list[0],hp->h_length); } else { addrServer.sin_addr.s_addr=inet_addr(strServer); } int bytesSend,bytesRecv,nLen; nLen = sizeof(SOCKADDR_IN); //初始化SNTP协议的数据包 InitData(); //发送请求 bytesSend = sendto(server,(char *)data, sizeof(data), 0, (sockaddr *)&addrServer, sizeof(SOCKADDR_IN)); if(bytesSend != sizeof(data)) { strMsg.Format(_T("Error at sendto %s bytes:%d Code:%d"), inet_ntoa(addrServer.sin_addr),bytesSend,WSAGetLastError()); AfxMessageBox(strMsg,MB_ICONERROR); WSACleanup(); return FALSE; } nLen = sizeof(SOCKADDR_IN); //接收返回的请求 bytesRecv = recvfrom(server,(char *)data, sizeof(data), 0, (sockaddr *)&addrServer, &nLen); if(bytesRecv != sizeof(data)) { strMsg.Format(_T("Error at recvfrom bytes:%d Code:%d"),bytesRecv,WSAGetLastError()); AfxMessageBox(strMsg,MB_ICONERROR); WSACleanup(); return FALSE; } //分析SNTP协议的数据包,计算时间偏差 AnalyseData(); strMsg.Format(_T("零时区时间为: /n/ /r 客户端发送时间T1:%04d-%02d-%02d %02d:%02d:%02d.%03d/n/ /r 服务端接收时间T2:%04d-%02d-%02d %02d:%02d:%02d.%03d/n/ /r 服务端发送时间T3:%04d-%02d-%02d %02d:%02d:%02d.%03d/n/ /r 客户端接收时间T4:%04d-%02d-%02d %02d:%02d:%02d.%03d/n/ /r 时间偏差为:%dms/n/ /r/r是否要同步设置本机时间/n"), T1.wYear,T1.wMonth,T1.wDay,T1.wHour,T1.wMinute,T1.wSecond,T1.wMilliseconds, T2.wYear,T2.wMonth,T2.wDay,T2.wHour,T2.wMinute,T2.wSecond,T2.wMilliseconds, T3.wYear,T3.wMonth,T3.wDay,T3.wHour,T3.wMinute,T3.wSecond,T3.wMilliseconds, T4.wYear,T4.wMonth,T4.wDay,T4.wHour,T4.wMinute,T4.wSecond,T4.wMilliseconds, nTimeOff); OutputDebugString(strMsg); //显示结果,并询问是否需要同步本机时间 if(IDYES == MessageBox(NULL,strMsg,_T("是否要设置本机时间"),MB_YESNO | MB_ICONQUESTION)) { SYSTEMTIME st1,st2;; //获取本机修改时间前的时间 GetLocalTime(&st1); //设置时间 int bRet = MySetLocalTime(); if(bRet) { //获取本机修改时间后的时间 GetLocalTime(&st2); strMsg.Format(_T("/r当前时间:%04d-%02d-%02d %02d:%02d:%02d.%03d/n/ /r修改时间:%04d-%02d-%02d %02d:%02d:%02d.%03d/n"), st1.wYear,st1.wMonth,st1.wDay,st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds, st2.wYear,st2.wMonth,st2.wDay,st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds); //显示修改本机时间的结果 MessageBox(NULL,strMsg,_T("信息"),MB_OK | MB_ICONINFORMATION ); } else { strMsg.Format(_T("Error at SetSystemTime Code:%d"),GetLastError()); AfxMessageBox(strMsg,MB_ICONERROR); } } //释放 WSACleanup(); return TRUE; } /* **------------------------------------------------------------ ** 函数: ** void CSNTPClient::InitData() ** ** 参数: ** 无 ** ** 功能: ** ** 赋值T1,初始化SNTP协议版本号等,并填充T3数据段 ** ** 返回: ** 无 ** **------------------------------------------------------------ */ void CSNTPClient::InitData() { SYSTEMTIME st; //获取本机的零时区时间 GetSystemTime(&st); //保存到T1变量中,即本机发送请求的时间 T1 = st; unsigned __int64 temp; //初始化SNTP协议的版本号等 ZeroMemory(data,sizeof(data)); data[0] = htonl((LI << 30) | (VN << 27) | (MODE << 24) | (STRATUM << 16) | (POLL << 8) | (PREC & 0xff)); data[1] = htonl(1<<16); /* Root Delay (seconds) */ data[2] = htonl(1<<16); /* Root Dispersion (seconds) */ //获取T1时间戳的总毫秒数 temp = GetTotalMilliseconds(st); //根据SNTP协议的规定填充到数据包的T3位置处 data[offT3] = htonl(DWORD(temp / 1000)); data[offT3 + 1] = htonl(DWORD(temp % 1000 * 0x100000000L / 1000 )); } /* **------------------------------------------------------------ ** 函数: ** unsigned __int64 CSNTPClient::GetTotalMilliseconds(SYSTEMTIME st) ** ** 参数: ** SYSTEMTIME st 需要要计算的SYSTEMTIME结构体 ** ** 功能: ** ** 计算的SYSTEMTIME结构体SNTP协议时间的总毫秒数 ** ** 返回: ** SNTP协议时间的总毫秒数 ** **------------------------------------------------------------ */ unsigned __int64 CSNTPClient::GetTotalMilliseconds(SYSTEMTIME st) { FILETIME ft; //把SYSTEMTIME结构的时间转化为FILETIME结构的时间 SystemTimeToFileTime(&st,&ft); unsigned __int64 temp; //利用FILETIME结构计算出时间的毫秒数 temp = unsigned __int64(ft.dwHighDateTime * 0x100000000L + ft.dwLowDateTime) / 10000L; //返回SNTP协议的时间的毫秒数 return temp - nSNTPStartMilliseconds; } /* **------------------------------------------------------------ ** 函数: ** void CSNTPClient::AnalyseData() ** ** 参数: ** 无 ** ** 功能: ** ** 赋值T4,分析服务器返回的数据包,获取T2,T3,并计算偏差 ** ** 返回: ** 无 ** **------------------------------------------------------------ */ void CSNTPClient::AnalyseData() { SYSTEMTIME st; //获取本机的零时区时间 GetSystemTime(&st); //保存到T4变量中,即本机接收数据包的时间 T4 = st; //获取数据包中服务端接收到数据包的时间,保存到T2变量中 T2 = ConverToSystemTime(offT2); //获取数据包中服务端发送数据包给客户端的时间,保存到T3变量中 T3 = ConverToSystemTime(offT3); //计算本机与服务器的时间偏差 nTimeOff = int((GetTotalMilliseconds(T2) - GetTotalMilliseconds(T1))+ (GetTotalMilliseconds(T3) - GetTotalMilliseconds(T4))) /2; } /* **------------------------------------------------------------ ** 函数: ** SYSTEMTIME CSNTPClient::ConverToSystemTime(unsigned int offset) ** ** 参数: ** unsigned int offset 协议数据包偏差 ** ** 功能: ** ** 根据偏差计算SNTP协议传递的时间 ** ** 返回: ** 计算出的SYSTEMTIME结构体 ** **------------------------------------------------------------ */ SYSTEMTIME CSNTPClient::ConverToSystemTime(unsigned int offset) { unsigned __int64 temp; FILETIME ft; SYSTEMTIME st; //计算出SNTP协议传递的时间(单位:100/1000000000秒) temp = unsigned __int64(ntohl(data[offset])) * 10000000L + unsigned __int64(ntohl(data[offset + 1])) * 10000000L / 0x100000000L; //加上SNTP协议的时间起点,转换为传递的零时区时间 temp += nSNTPStartMilliseconds * 10000L; //转换为FILETIME结构时间 ft.dwHighDateTime = DWORD(temp / 0x100000000L); ft.dwLowDateTime = DWORD(temp % 0x100000000L); //把FILETIME结构转换为SYSTEMTIME结构 FileTimeToSystemTime(&ft,&st); return st; } /* **------------------------------------------------------------ ** 函数: ** BOOL CSNTPClient::MySetLocalTime() ** ** 参数: ** 无 ** ** 功能: ** ** 根据时间偏差计算出需要同步的时间,并设置本机时间 ** ** 返回: ** 设置本机时间成功返回(TRUE),失败返回(FALSE) ** **------------------------------------------------------------ */ BOOL CSNTPClient::MySetLocalTime() { SYSTEMTIME st; FILETIME ft; unsigned __int64 temp; //获取本机现在的时间,这个时间带有时区信息 GetLocalTime(&st); //获取减去了SNTP协议起点时间的总毫秒数 temp = GetTotalMilliseconds(st); //加上SNTP协议起点时间的总毫秒数 temp += nSNTPStartMilliseconds; //加上本机与服务器的时间偏差 temp += nTimeOff; //把单位毫秒转为100/1000000000秒 temp *= 10000L; //转换为FILETIME结构时间 ft.dwHighDateTime =DWORD(temp / 0x100000000L); ft.dwLowDateTime = DWORD(temp % 0x100000000L); //把FILETIME结构的时间转化为SYSTEMTIME结构的时间 FileTimeToSystemTime(&ft,&st); //返回设置本机时间的结果 return SetLocalTime(&st); }

你可能感兴趣的:(毕设VC做的一个SNTP协议的客户端类CSNTPClient)