使用易語(yǔ)言獲取NTP服務(wù)器時(shí)間:簡(jiǎn)單實(shí)現
本文將針對使用易語(yǔ)言獲取NTP服務(wù)器時(shí)間:簡(jiǎn)單實(shí)現進(jìn)行詳細闡述,主要從四個(gè)方面展開(kāi),包括獲取NTP服務(wù)器地址、連接NTP服務(wù)器、獲取NTP服務(wù)器時(shí)間、并將時(shí)間轉換成本地時(shí)間的實(shí)現過(guò)程。
1、獲取NTP服務(wù)器地址
在使用易語(yǔ)言獲取NTP服務(wù)器時(shí)間之前,需要先獲取NTP服務(wù)器的地址??梢酝ㄟ^(guò)搜索引擎查詢(xún)常用的公共NTP服務(wù)器地址,也可以通過(guò)代碼從中國科學(xué)院國家授時(shí)中心獲取NTP服務(wù)器地址:
const NTPSERVER = "time.stdtime.gov.tw"; // 臺灣標準時(shí)間服務(wù)器地址 function GetNTPServerIP():string; var addr: array[0..255] of Char; hints: TAddrInfo; AddrInfo, Ai: PAddrInfo; begin FillChar(hints, Sizeof(hints), 0); hints.ai_family := AF_INET; hints.ai_socktype := SOCK_STREAM; hints.ai_protocol := IPPROTO_TCP; if GetAddrInfo(NTPSERVER, http, @hints, @AddrInfo) <> 0 then begin Result := ; Exit; end; Ai := AddrInfo; while Ai <> nil do begin WSAAddressToString(Ai^.ai_addr, Ai^.ai_addrlen, nil, addr, AddrLen); Result := addr; Inc(Result); Inc(Ai); end; FreeAddrInfo(AddrInfo); SetLength(Result, Length(Result) - 1); end;上述代碼中,GetAddrInfo函數用于獲得地址信息,WSAAddressToString函數用于將地址轉換為字符串。獲取到NTP服務(wù)器的IP地址后,就可以進(jìn)行連接操作。
2、連接NTP服務(wù)器
連接NTP服務(wù)器需要建立套接字,并通過(guò)Socket API調用進(jìn)行連接。連接建立后就可以向服務(wù)器發(fā)送時(shí)間請求,并接收服務(wù)器返回的時(shí)間戳。
const NTPPORT = 123; // NTP服務(wù)器UDP端口號 type TNTPClient = packed record Head:Byte; // NTP協(xié)議頭信息 Version:Byte; // 版本號 Mode:Byte; // 模式 Stratum:Byte; // 層數 Poll:Byte; // 請求間隔,以2的冪次表示 Precision:Byte; // 時(shí)鐘精度 RootDelay:LongInt; // 根距離 RootDispersion:LongInt; // 根離散 ReferenceClockID:LongInt; // 引用時(shí)鐘ID ReferenceTimeStamp:TDateTime; // 引用時(shí)間戳 OriginTimeStamp:TDateTime; // 請求發(fā)送時(shí)間戳 ReceiveTimeStamp:TDateTime; // 請求接收時(shí)間戳 TransmitTimeStamp:TDateTime; // 請求響應時(shí)間戳 end; function GetNTPTime():TDateTime; var clientAddr: sockaddr_in; clientSocket: TSocket; ntp: TNTPClient; ntpData, rawData: array[0..255] of byte; timeStamp: LongWord; len : integer; begin Result := 0; FillChar(ntp, sizeof(ntp), 0); clientSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (clientSocket = INVALID_SOCKET) then Exit; clientAddr.sin_family := AF_INET; clientAddr.sin_port := htons(NTPPORT); clientAddr.sin_addr.s_addr := inet_addr(PChar(GetNTPServerIP())); ntp.Head := $23; ntp.Version := $03; ntp.Mode := $03; timeStamp := htonl(TimeToTimeStamp(now).Time); Move(timeStamp, ntp.TransmitTimeStamp, SizeOf(timeStamp)); len := SizeOf(sockaddr_in); if sendto(clientSocket, ntp, SizeOf(ntp), 0, @clientAddr, len) < 0 then begin closesocket(clientSocket); Exit; end; len := recvfrom(clientSocket, rawData, SizeOf(rawData), 0, @clientAddr, len); closesocket(clientSocket); if len < 0 then Exit; Move(rawData, ntpData, len); Result := TimeStampToDateTime(ntpData[40..43]); // 解析NTP服務(wù)器發(fā)來(lái)的時(shí)間戳 end;
3、獲取NTP服務(wù)器時(shí)間
通過(guò)連接到NTP服務(wù)器并發(fā)送請求,可以接收到返回的時(shí)間戳。為了獲取精確的時(shí)間信息,需要將時(shí)間戳轉換成當地的時(shí)間。
function GetNTPTime():TDateTime;begin //前面的代碼與上述內容相同,省略掉 // 解析NTP服務(wù)器發(fā)來(lái)的時(shí)間戳 Result := TimeStampToDateTime(ntpData[40..43]); Result := Result + ((ntpData[43] * 256 + ntpData[44]) / 4294967296) / 24; Result := Result + ((ntpData[42] * 256 + ntpData[43]) mod 65536) / 1440; end;
4、將時(shí)間轉換成本地時(shí)間
獲取到的時(shí)間戳是NTP服務(wù)器標準時(shí)間,需要將其轉換成本地時(shí)間??梢酝ㄟ^(guò)Delphi中內置的函數LocalTime或UniversalTime進(jìn)行轉換。其中,LocalTime函數將時(shí)間戳轉換為當前時(shí)區的本地時(shí)間,而UniversalTime函數則將時(shí)間戳轉換為協(xié)調世界時(shí)(UTC)時(shí)間。
var ntpTime: TDateTime; // NTP服務(wù)器時(shí)間 localTime: TDateTime; // 本地時(shí)間 begin ntpTime:= GetNTPTime(); localTime:= LocalTimeToDateTime(ntpTime); ShowMessage(FormatDateTime(yyyy-MM-dd hh:mm:ss, localTime)); end;通過(guò)上述的實(shí)現步驟,就可以使用易語(yǔ)言獲取NTP服務(wù)器時(shí)間了。
總結:
本文針對使用易語(yǔ)言獲取NTP服務(wù)器時(shí)間:簡(jiǎn)單實(shí)現進(jìn)行了詳細地闡述,包括獲取NTP服務(wù)器地址、連接NTP服務(wù)器、獲取NTP服務(wù)器時(shí)間、將時(shí)間轉換成本地時(shí)間。通過(guò)仔細閱讀文章,讀者已經(jīng)可以了解使用易語(yǔ)言獲取NTP服務(wù)器時(shí)間的基本過(guò)程和方法。在實(shí)際開(kāi)發(fā)中,讀者可以根據自己的需要進(jìn)行進(jìn)一步的優(yōu)化和完善。