網(wǎng)絡(luò)授時(shí)服務(wù)是一些網(wǎng)絡(luò)上的時(shí)間服務(wù)器提供的時(shí)間,一般用于本地時(shí)鐘同步。 授時(shí)服務(wù)有很多種,一般我們選擇RFC-868。這個(gè)協(xié)議的工作流程是:(S代表Server,C代表Client)
S: 檢測端口37
U: 連接到端口37
S: 以32位二進(jìn)制數(shù)發(fā)送時(shí)間
U: 接收時(shí)間
U: 關(guān)閉連接
S: 關(guān)閉連接
協(xié)議非常簡單,用TCP連接上后,服務(wù)器直接把時(shí)間發(fā)送回來。發(fā)送的是從1900年1月1日午夜到現(xiàn)在的秒數(shù)。
使用luasocket
實(shí)現(xiàn)的方案有很多種,Lua不一定是最簡單的,選擇只是出于個(gè)人興趣。直接上代碼吧
-----------------------------------------------------------------------------
-- Network Time Protocal
-- Author: ani_di
-----------------------------------------------------------------------------
package.cpath = package.cpath .. ';D:\\tools\\Lua\\5.1\\clibs\\?.dll;?.dll'
local socket = 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"}
function nstol(str)
assert(str and #str == 4)
local t = {str:byte(1,-1)}
local n = 0
for k = 1, #t do
n= n*256 + t[k]
end
return n
end
-- get time from a ip address, use tcp protocl
function gettime(ip)
print('connect ', ip)
local tcp = socket.tcp()
tcp:settimeout(10)
tcp:connect(ip, 37)
success, time = pcall(nstol, tcp:receive(4))
tcp:close()
return success and time or nil
end
function nettime()
for _, ip in pairs(server_ip) do
time = gettime(ip)
if time then
return time
end
end
end
代碼原理不細(xì)說,非常簡單。唯一值得一提的是socket庫包含。最開始用的這句 require "socket"
在解釋器中表現(xiàn)很好,但在用C中調(diào)用會(huì)找不到相應(yīng)的module。錯(cuò)誤提示
no field package.preload['socket']
no file '.\socket.lua'
no file 'F:\Projects\Lua\nettime\lua\socket.lua'
no file 'F:\Projects\Lua\nettime\lua\socket\init.lua'
no file 'F:\Projects\Lua\nettime\socket.lua'
no file 'F:\Projects\Lua\nettime\socket\init.lua'
no file 'D:\tools\Lua\5.1\lua\socket.luac'
no file '.\socket.dll'
no file '.\socket51.dll'
no file 'F:\Projects\Lua\nettime\socket.dll'
no file 'F:\Projects\Lua\nettime\socket51.dll'
no file 'F:\Projects\Lua\nettime\clibs\socket.dll'
no file 'F:\Projects\Lua\nettime\clibs\socket51.dll'
no file 'F:\Projects\Lua\nettime\loadall.dll'
no file 'F:\Projects\Lua\nettime\clibs\loadall.dll'.
網(wǎng)上也有好多類似的提問,大抵是沒仔細(xì)看作者的Guide。顯著的有這么一句
The other two environment variables instruct the compatibility module to look for dynamic libraries and extension modules in the appropriate directories and with the appropriate filename extensions.>
LUAPATH=/?.lua;?.lua LUACPATH=/?.dll;?.dll
至于"socket.core",windows默認(rèn)安裝位于“\socket\core.dll”。
C宿主調(diào)用
#include stdio.h>
#include string.h>
#include lua.h>
#include lauxlib.h>
#include lualib.h>
#include time.h>
#include Windows.h>
int load(lua_State* L, const char* func, unsigned int* utc) {
lua_getglobal(L, func);
if (lua_pcall(L, 0, 1, 0)) {
printf("Error Msg pcall %s.\n", lua_tostring(L, -1));
return -1;
}
if (!lua_isnumber(L,-1)) {
printf("time should be a number\n" );
return -2;
}
*utc = lua_tonumber(L,-1);
lua_pop(L, -1);
return 0;
}
void TimetToFileTime( time_t t, LPFILETIME pft )
{
LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
pft->dwLowDateTime = (DWORD) ll;
pft->dwHighDateTime = ll >>32;
}
int main()
{
lua_State* L = luaL_newstate();
unsigned int utc = 0;
luaL_openlibs(L);
if (luaL_loadfile(L, "nettime.lua") || lua_pcall(L, 0, 0, 0)) {
printf("Error Msg load %s.\n", lua_tostring(L, -1));
return -1;
}
do {
if(load(L,"nettime", utc) == 0) {
time_t tt = utc - 2208988800L;
SYSTEMTIME st;
FILETIME ft;
TimetToFileTime(tt, ft);
if (FileTimeToSystemTime(ft, st))
{
printf("Today is: %d-%d-%d\n", st.wYear, st.wMonth, st.wDay);
SetSystemTime(st);
}
break;
} else {
puts("No network!");
Sleep(10000);
}
} while (1);
lua_close(L);
return 0;
}