Lua获取网络时间(获取时间同步服务器的时间)
网络授时服务是一些网络上的时间服务器提供的时间,一般用于本地时钟同步。授时服务有很多种,一般我们选择RFC-868。这个协议的工作流程是:(S代表Server,C代表Client)
S:检测端口37
U:连接到端口37
S:以32位二进制数发送时间
U:接收时间
U:关闭连接
S:关闭连接
协议非常简单,用TCP连接上后,服务器直接把时间发送回来。发送的是从1900年1月1日午夜到现在的秒数。
使用luasocket
实现的方案有很多种,Lua不一定是最简单的,选择只是出于个人兴趣。直接上代码吧
----------------------------------------------------------------------------- --NetworkTimeProtocal --Author:ani_di ----------------------------------------------------------------------------- package.cpath=package.cpath..';D:\\tools\\Lua\\5.1\\clibs\\?.dll;?.dll' localsocket=require"socket.core" server_ip={ --"129.6.15.29", "132.163.4.101", "132.163.4.102", "132.163.4.103", "128.138.140.44", "192.43.244.18", "131.107.1.10", "66.243.43.21", "216.200.93.8", "208.184.49.9", "207.126.98.204", "207.200.81.113", "205.188.185.33"} functionnstol(str) assert(strand#str==4) localt={str:byte(1,-1)} localn=0 fork=1,#tdo n=n*256+t[k] end returnn end --gettimefromaipaddress,usetcpprotocl functiongettime(ip) print('connect',ip) localtcp=socket.tcp() tcp:settimeout(10) tcp:connect(ip,37) success,time=pcall(nstol,tcp:receive(4)) tcp:close() returnsuccessandtimeornil end functionnettime() for_,ipinpairs(server_ip)do time=gettime(ip) iftimethen returntime end end end
代码原理不细说,非常简单。唯一值得一提的是socket库包含。最开始用的这句require"socket"
在解释器中表现很好,但在用C中调用会找不到相应的module。错误提示
nofieldpackage.preload['socket'] nofile'.\socket.lua' nofile'F:\Projects\Lua\nettime\lua\socket.lua' nofile'F:\Projects\Lua\nettime\lua\socket\init.lua' nofile'F:\Projects\Lua\nettime\socket.lua' nofile'F:\Projects\Lua\nettime\socket\init.lua' nofile'D:\tools\Lua\5.1\lua\socket.luac' nofile'.\socket.dll' nofile'.\socket51.dll' nofile'F:\Projects\Lua\nettime\socket.dll' nofile'F:\Projects\Lua\nettime\socket51.dll' nofile'F:\Projects\Lua\nettime\clibs\socket.dll' nofile'F:\Projects\Lua\nettime\clibs\socket51.dll' nofile'F:\Projects\Lua\nettime\loadall.dll' nofile'F:\Projects\Lua\nettime\clibs\loadall.dll'.
网上也有好多类似的提问,大抵是没仔细看作者的Guide。显著的有这么一句
Theothertwoenvironmentvariablesinstructthecompatibilitymoduletolookfordynamiclibrariesandextensionmodulesintheappropriatedirectoriesandwiththeappropriatefilenameextensions.>
LUAPATH=/?.lua;?.luaLUACPATH=/?.dll;?.dll
至于"socket.core",windows默认安装位于“\socket\core.dll”。
C宿主调用
#include<stdio.h> #include<string.h> #include<lua.h> #include<lauxlib.h> #include<lualib.h> #include<time.h> #include<Windows.h> intload(lua_State*L,constchar*func,unsignedint*utc){ lua_getglobal(L,func); if(lua_pcall(L,0,1,0)){ printf("ErrorMsgpcall%s.\n",lua_tostring(L,-1)); return-1; } if(!lua_isnumber(L,-1)){ printf("timeshouldbeanumber\n"); return-2; } *utc=lua_tonumber(L,-1); lua_pop(L,-1); return0; } voidTimetToFileTime(time_tt,LPFILETIMEpft) { LONGLONGll=Int32x32To64(t,10000000)+116444736000000000; pft->dwLowDateTime=(DWORD)ll; pft->dwHighDateTime=ll>>32; } intmain() { lua_State*L=luaL_newstate(); unsignedintutc=0; luaL_openlibs(L); if(luaL_loadfile(L,"nettime.lua")||lua_pcall(L,0,0,0)){ printf("ErrorMsgload%s.\n",lua_tostring(L,-1)); return-1; } do{ if(load(L,"nettime",&utc)==0){ time_ttt=utc-2208988800L; SYSTEMTIMEst; FILETIMEft; TimetToFileTime(tt,&ft); if(FileTimeToSystemTime(&ft,&st)) { printf("Todayis:%d-%d-%d\n",st.wYear,st.wMonth,st.wDay); SetSystemTime(&st); } break; }else{ puts("Nonetwork!"); Sleep(10000); } }while(1); lua_close(L); return0; }