ntp client

最进写一个ntp客户端,获得时间服务器,好多地方都用,挺好的,协议部分网上多得是,还行,误差秒及的;

 

#define EPOCH_DIFF ((unsigned long) 86400 * (365 * 70 + 17))

double synctime (char *server_name)
{
 int i, r, udp;
 static int firstsync = 1;
 char buf[61];
 ssize_t len;
 static time_t errstart = 0;
 static struct timeval tv1, tv2, tv3, tv4, tvnew, cmpval;
 struct timezone tz;
 double t1, t2, t3, t4, toff, tnew;
 time_t now;
 struct sockaddr_in server;
 struct in_addr server_addr;
 struct hostent *server_hostent;
 int count;
 fd_set rd_fd;
 fd_set wr_fd;
 struct timeval time_out;
 int mark;
 mark = 0;
 r = inet_aton (server_name, &server_addr);
 if (r == 0)
 {
  server_hostent = gethostbyname (server_name);
  if(server_hostent == NULL)
  {
   return 0;
  }
  server_addr.s_addr =
   ((server_hostent->h_addr_list[0][3] << 24) & 0xFF000000) |
   ((server_hostent->h_addr_list[0][2] << 16) & 0x00FF0000) |
   ((server_hostent->h_addr_list[0][1] << 8)  & 0x0000FF00) |
   (server_hostent->h_addr_list[0][0]         & 0x000000FF);
 }
 server.sin_family = AF_INET;
 server.sin_addr = server_addr;
 server.sin_port = htons (SNTP_PORT);
 udp = socket (PF_INET, SOCK_DGRAM, 0);
 r = connect (udp, (struct sockaddr*) &server, sizeof (server));
 if (r == -1)
 {
  now = time (NULL);
  if (errstart == 0)
   errstart = now;
  r = close (udp);
  return 0;
 }
 for (i = 0; i < 61; i++)
  buf[i] = 0;
 buf[0] = (0 << 6) | (1 << 3) | 3;
 gettimeofday (&tv1, &tz);
 t1 = (double) tv1.tv_sec + (double) tv1.tv_usec / 1000000;
 memcpy (&buf[40], tonetnum ((unsigned long) tv1.tv_sec + EPOCH_DIFF), 4);
 memcpy (&buf[44], tonetnum (usec2frac (tv1.tv_usec)), 4);
 count = 0;
 while(1){
  FD_ZERO(&rd_fd);
  FD_ZERO(&wr_fd);
  time_out.tv_sec = 0;
  time_out.tv_usec = 500000;
  FD_SET(udp, &rd_fd);
  FD_SET(udp, &wr_fd);
  len = send (udp, buf, 48, 0);
  if (len == -1)
  {
   printf("send error/n");
   now = time (NULL);
   if (errstart == 0)
    errstart = now;
   r = close (udp);
   return 0;
  }
  if(count++ > 20){
   printf("count too much/n");
   close(udp);
   return 0;
  }
  if(select(udp + 1, &rd_fd, NULL, NULL, &time_out) <= 0){
   continue;
  }
  if(FD_ISSET(udp, &rd_fd)){
   len = recv (udp, &buf, 60, 0);
   if (len == -1)
   {
    now = time(NULL);
    if (errstart == 0)
     errstart = now;
    r = close (udp);
    return 0;
   }
   gettimeofday (&tv4, &tz);
   t4 = (double) tv4.tv_sec + (double) tv4.tv_usec / 1000000;
   tv2.tv_sec = fromnetnum (&buf[32]) - EPOCH_DIFF;
   tv2.tv_usec = frac2usec (fromnetnum (&buf[36]));
   t2 = (double) tv2.tv_sec + (double) tv2.tv_usec / 1000000;
   tv3.tv_sec = fromnetnum (&buf[40]) - EPOCH_DIFF;
   tv3.tv_usec = frac2usec (fromnetnum (&buf[44]));
   t3 = (double) tv3.tv_sec + (double) tv3.tv_usec / 1000000;
   toff = (t2 + t3 - t1 - t4) / 2;
   if(mark == 0){
    tnew = t4 + toff;
    tvnew.tv_usec = (long long) (tnew * 1000000) % 1000000;
    tvnew.tv_sec = ((long long) (tnew * 1000000) - tvnew.tv_usec) / 1000000;
    settimeofday (&tvnew, &tz);
      mark = 1;
   }
   if(mark == 1){
    cmpval.tv_usec = (long long) (tnew * 1000000) % 1000000;
    cmpval.tv_sec = ((long long) (tnew * 1000000) - cmpval.tv_usec) / 1000000;
    if(cmpval.tv_sec - tvnew.tv_sec < 25){
     
     settimeofday (&cmpval, &tz);

     nowtime();
     close(udp);
     return toff;
    }else{
     mark = 0;
     continue;
    }
   }
  }
 }
}

 

 

就是这样的,配一下协议头,然后发送给公网上的ntp_server,有时候第一次得到的是不正确的时间,所以取两次时间!!!!!

您可以使用Windows Socket API来编写一个简单的NTP客户端,以下是一个VC++示例代码: ```c++ #include <iostream> #include <WinSock2.h> #include <windows.h> #include <time.h> #pragma comment(lib, "Ws2_32.lib") #define NTP_TIMESTAMP_DELTA 2208988800ull int main() { // 初始化Winsock WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != 0) { std::cout << "WSAStartup failed with error: " << iResult << std::endl; return 1; } // 创建UDP套接字 SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) { std::cout << "socket failed with error: " << WSAGetLastError() << std::endl; WSACleanup(); return 1; } // 设置NTP服务器地址和端口 SOCKADDR_IN serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(123); serverAddr.sin_addr.s_addr = inet_addr("time.nist.gov"); // 构造NTP请求报文 char ntpPacket[48] = {0}; ntpPacket[0] = 0x1b; // 发送NTP请求 iResult = sendto(sock, ntpPacket, sizeof(ntpPacket), 0, (SOCKADDR *)&serverAddr, sizeof(serverAddr)); if (iResult == SOCKET_ERROR) { std::cout << "sendto failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); WSACleanup(); return 1; } // 接收NTP响应 char recvBuf[1024] = {0}; iResult = recv(sock, recvBuf, sizeof(recvBuf), 0); if (iResult == SOCKET_ERROR) { std::cout << "recv failed with error: " << WSAGetLastError() << std::endl; closesocket(sock); WSACleanup(); return 1; } // 解析NTP响应 unsigned long long ntpTime = 0; memcpy(&ntpTime, &recvBuf[40], sizeof(ntpTime)); ntpTime = ntohl(ntpTime); ntpTime -= NTP_TIMESTAMP_DELTA; time_t unixTime = (time_t)ntpTime; std::cout << "Current time is " << ctime(&unixTime) << std::endl; // 关闭套接字并清理 closesocket(sock); WSACleanup(); return 0; } ``` 此代码使用了time.nist.gov作为NTP服务器,您可以根据需要更改。需要注意的是,NTP协议使用的是UTC时间,因此需要进行时区转换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值