注册 登录
编程论坛 VFP论坛

连接NTP服务器,获取网络时间,请赐教

sych 发布于 2022-09-20 15:45, 2761 次点击
SET CENTURY on
SET DATE ANSI
SET HOURS TO 24
CLEAR
?1
fh=_GetNetTime("128.138.140.44",13)  &&这个成功,以下均失败,不知道为什么
?zh(fh)

?2
fh=_GetNetTime("s1a.time.,123)
?zh(fh)

?"2-1"
fh=_GetNetTime("114.118.7.163",123)
?zh(fh)

?"2-2"
fh=_GetNetTime("ntp.ntsc.,123)
?zh(fh)

?"3-1"
fh=_GetNetTime("139.199.215.251",123)
?zh(fh)

?"3-2"
fh=_GetNetTime("ntp.,123)
?zh(fh)
retu

FUNCTION _GetNetTime(szNtpIP, ddNtpPort)
LOCAL stWsaData, stSockAddr, szBuffer, dhSocket
LOCAL i, ddLen,ret

DECLARE LONG WSAStartup  IN "Ws2_32" LONG, STRING@
DECLARE LONG WSACleanup  IN "Ws2_32"
DECLARE LONG socket      IN "Ws2_32" LONG, LONG, LONG
DECLARE LONG connect     IN "Ws2_32" LONG, STRING@, LONG
DECLARE LONG recv        IN "Ws2_32" LONG, STRING@, LONG, LONG
DECLARE LONG closesocket IN "Ws2_32" LONG
DECLARE LONG inet_addr   IN "Ws2_32" STRING@
DECLARE LONG htons       IN "Ws2_32" LONG
DECLARE INTEGER gethostbyname in WSOCK32 String
DECLARE LONG inet_ntoa     IN "Ws2_32" LONG

stWsaData  = REPLICATE(0h00, 398)
szBuffer   = REPLICATE(0h00, 256)
stSockAddr = REPLICATE(0h00, 16)

WSAStartup(0x202, @stWsaData)
dhSocket = socket(2, 1, 6)
IF ISDIGIT(szNtpIP)
    stSockAddr = 0h0200;
        + BINTOC(htons(ddNtpPort), "2RS");
        + BINTOC(inet_addr(@szNtpIP), "4RS");
        + REPLICATE(0h00, 8)
else
    RET = CTOBIN(SYS(2600, gethostbyname(@szNtpIP) + 12, 4), "4RS")  &&偏移12,IP地址列表
    RET = CTOBIN(SYS(2600, RET, 4), "4RS")  &&IP地址
    stSockAddr = 0h0200;
        + BINTOC(htons(ddNtpPort), "2RS");
        + SYS(2600, RET, 4);
        + REPLICATE(0h00, 8)
endif
ddLen  = 0
IF connect(dhSocket, @stSockAddr, LEN(stSockAddr)) != -1
    FOR i = 1 TO 9
        ddLen = recv(dhSocket, @szBuffer, LEN(szBuffer), 0)
        IF ddLen != -1
            EXIT
        ENDIF
    ENDFOR
ENDIF
closesocket(dhSocket)
WSACleanup()
IF ddLen > 0
    szBuffer = LEFT(szBuffer, ddLen)
    RETURN szBuffer
ELSE
*        MESSAGEBOX("网络异常,时间同步失败")
    RETURN ""
ENDIF
ENDFUNC

PROCEDURE zh
LPARAMETERS szutc
IF EMPTY(szutc)
else
    ddYear   = INT(VAL(SUBSTR(szUTC, 8, 2))) + 2000
    ddMonth  = INT(VAL(SUBSTR(szUTC, 11, 2)))
    ddDay    = INT(VAL(SUBSTR(szUTC, 14, 2)))
    ddHour   = INT(VAL(SUBSTR(szUTC, 17, 2)))
    ddMinute = INT(VAL(SUBSTR(szUTC, 20, 2)))
    ddSecond = INT(VAL(SUBSTR(szUTC, 23, 2)))
    RETURN DATETIME(ddYear,ddMonth,ddDay,ddHour,ddMinute,ddSecond)+8*3600
endif
RETURN ""
23 回复
#2
厨师王德榜2022-09-20 16:23
中科院这个,改服务了吧,看这个 https://www.
#3
吹水佬2022-09-20 17:00
这个也可以
https://www.
https://www.
#4
sych2022-09-20 17:21
吹版,你提供的都可以
只是我上面的代码怎么会有的正常,有的失败(代码是我网上抄的)
#5
sych2022-09-20 17:23
关键是,国内的一个也不行,第一个是国外的
#6
sych2022-09-20 17:27
都不介绍连接端口
#7
sych2022-09-20 17:30
fh=_GetNetTime("time.nist.gov",13)
不屑努力,又测试成功一个
#8
吹水佬2022-09-20 17:37
回复 4楼 sych
3楼的通过WEB就可以获取,相对简单些
#9
kangss2022-09-21 11:11
要求精度不高,可以试试百度
CLEAR
ON ERROR

xmlHttp = CREATEOBJECT("Microsoft.XMLHTTP")
xmlhttp.open("get","https://www.baidu.com", .F.)
xmlHttp.send

m._datetime = UPPER(xmlHttp.getallResponseHeaders)
m._datetime = ALLTRIM(STREXTRACT(m._datetime, "DATE:", CHR(13)))

* 星期一:Mon.=Monday星期二:Tues.=Tuesday星期三:Wed.=Wednesday星期四:Thur.=Thursday星期五:Fri.=Friday星期六:Sat.=Saturday 星期天:Sun.=Sunday
* 一月=JAN. Jan.=January    二月=FEB. Feb.=February        三月=MAR. Mar.=March        四月=APR. Apr.=April        五月=MAY May=May        六月=JUN. Jun.=June
* 七月=JUL. Jul.=July        八月=AUG. Aug.=August        九月=SEP. Sept.=September    十月=OCT. Oct.=October        十一月=NOV. Nov.=November    十二月=DEC. Dec.=December

LOCAL m._年, m._月, m._日    && SAT, 10 OCT 2020 06:45:07 GMT

m._年 = STREXTRACT(m._datetime, SPACE(1), SPACE(1), 3)
m._月 = STREXTRACT(m._datetime, SPACE(1), SPACE(1), 2)

m._月 = ICASE(m._月 = "JAN", "1", m._月 = "FEB", "2", m._月 = "MAR", "3", m._月 = "APR", "4", m._月 = "MAY", "5", m._月 = "JUN", "6", ;
 m._月 = "JUL", "7", m._月 = "AUG", "8", m._月 = "SEP", "9", m._月 = "OCT", "10", m._月 = "NOV", "11", m._月 = "DEC", "12")

m._日 = STREXTRACT(m._datetime, SPACE(1), SPACE(1), 1)

m._datetime = CTOT(m._年 + "." + m._月 + "." +  m._日 + " " + STREXTRACT(m._datetime, SPACE(1), SPACE(1), 4)) + 8 * 60 * 60    &&     获取的时间差 8 小时
?_datetime


xmlhttp.open("Get","http://time.nist.gov:13/",.f.)
xmlhttp.send()
?xmlhttp.responsetext
#10
csyx2022-09-21 12:25
发完贴,发现跟楼上方法类同


[此贴子已经被作者于2022-9-21 12:30编辑过]

#11
my23182022-09-23 15:27
最简便方法,利用windows系统的时间同步功能,精度要求不高可以利用本地时间,要求高一些严谨一些,可以获取sql服务器时间,sql服务器时间可以同步授时网站时间。实际上,获取网络时间的目的一般是记录系统操作的时序时间。
#12
sych2022-09-23 17:44
结果不重要,只看过程
#13
sych2022-09-23 17:44
能用VFP实现,有成就感
#14
sych2022-09-24 20:32
https://blog.
看着简单,想改编成vfp却处处掣肘
#15
吹水佬2022-09-25 08:23
以下是引用sych在2022-9-24 20:32:28的发言:

https://blog.
看着简单,想改编成vfp却处处掣肘

200.205.253.254:123 这个NTP能用吗?
#16
sych2022-09-25 10:00
这个也不行,就差一个生成报文的代码,发送不是问题,接收也不是问题
#17
sych2022-09-25 10:02
原来的NTP服务器好像不 用发送报文,自动按UDP模式广播,而端口是123的是TCP连接,均需要先发送报文,才会返回报文
#18
sych2022-09-25 10:02
我猜的,具体远离不懂的
#19
sych2022-09-25 11:39
/* 构建 NTP 协议包 */
int ConstructPacket(char *Packet)
{
    char Version = 1;
    long SecondFrom1900;
    long Zero = 0;
    int Port;
    time_t timer;
   
    strcpy(Protocol,NTPV1);
    /* 判断协议版本 */
    if(strcmp(Protocol, NTPV1) || strcmp(Protocol,NTPV2) || strcmp(Protocol, NTPV3) || strcmp(Protocol, NTPV4))
    {
        Port = NTPPORT;
        Version = Protocol[6] - 0x30;
        Packet[0] = (Version << 3) | 3; //LI--Version--Mode
        Packet[1] = 0;                  //Startum
        Packet[2] = 0;                  //Poll interval
        Packet[3] = 0;                  //Precision

        /* 包括 Root delay、Root disperse 和 Ref Indentifier */
        memset(&Packet[4], 0, 12);
        /* 包括 Ref timestamp、Ori timastamp 和 Receive Timestamp */
        memset(&Packet[16], 0, 24);

        time(&timer);
        SecondFrom1900 = SecondBef1970 + (long)timer;
        SecondFrom1900 = htonl(SecondFrom1900);

        memcpy(&Packet[40], &SecondFrom1900, 4);
        memcpy(&Packet[44], &Zero, 4);
        return 48;
    }
    else    // time/udp
    {
        Port = TIMEPORT;
        memset(Packet, 0, 4);
        return 4;
    }
    return 0;
}
这个构建NTP协议包不知道怎么转到vfp中,看了你前一阵子写的构建struct类型的数据,还是理解不了
#20
吹水佬2022-09-25 16:18
以下是引用sych在2022-9-25 11:39:04的发言:
    ......
    strcpy(Protocol,NTPV1);
    /* 判断协议版本 */
    if(strcmp(Protocol, NTPV1) || strcmp(Protocol,NTPV2) || strcmp(Protocol, NTPV3) || strcmp(Protocol, NTPV4))
    {
        Port = NTPPORT;
        Version = Protocol[6] - 0x30;
        ......
        SecondFrom1900 = SecondBef1970 + (long)timer;
        ......
    }

代码好象不完整或有问题
1、strcpy(Protocol,NTPV1);
    #define NTPV1 "NTP/V1"
    相当于 Protocol = "NTP/V1"
2、if(strcmp(Protocol, NTPV1) || strcmp(Protocol,NTPV2) || strcmp(Protocol, NTPV3) || strcmp(Protocol, NTPV4))
    相当于 if (Protocol != NTPV1) or (Protocol != NTPV2) or (Protocol != NTPV3) or (Protocol != NTPV4)
    随便一个Protocol也可能满足条件
3、Version = Protocol[6] - 0x30;
    Protocol = "NTP/V1" 时,Protocol[6]应该是'\0'(字符串结束符),Protocol[0]是'N'
4、SecondFrom1900 = SecondBef1970 + (long)timer;
    SecondBef1970 从开始声明 double SecondBef1970; 之后就没有定义,在这时属未定义行为,带有不确定因素。
#21
sych2022-09-25 16:57
上面的代码是这个网址https://blog.里的
我先按你的代码改改试试
#22
sych2022-09-29 09:56
DECLARE LONG WSAStartup  IN "Ws2_32" LONG, STRING@
DECLARE LONG WSACleanup  IN "Ws2_32"
#INCLUDE vfp2c.h
SET LIBRARY TO vfp2c32.fll ADDITIVE

stWsaData  = REPLICATE(0h00, 398)
WSAStartup(0x202, @stWsaData)

?synctosntpserver("128.138.140.44",123)

WSACleanup()
RETURN
这个代码更简单
#23
吹水佬2022-09-29 11:46
以下是引用sych在2022-9-29 09:56:47的发言:

DECLARE LONG WSAStartup  IN "Ws2_32" LONG, STRING@
DECLARE LONG WSACleanup  IN "Ws2_32"
#INCLUDE vfp2c.h
SET LIBRARY TO vfp2c32.fll ADDITIVE

stWsaData  = REPLICATE(0h00, 398)
WSAStartup(0x202, @stWsaData)

?synctosntpserver("128.138.140.44",123)

WSACleanup()
RETURN
这个代码更简单

问题是vfp2c32.fll这个不简单了

#24
吹水佬2022-09-29 15:13
要简单就用CMD的w32tm,如:
w32tm /stripchart /computer:128.138.140.44 /dataonly /samples:1 /packetinfo
只有本站会员才能查看附件,请 登录


1