丁元
摘要:利用Internet傳送標(biāo)準(zhǔn)時(shí)間信息稱做網(wǎng)絡(luò)授時(shí)。目前網(wǎng)上有很多授時(shí)服務(wù)器,我們可以用高級(jí)語言寫一個(gè)在線對時(shí)器,獲取授時(shí)服務(wù)器上的時(shí)間并以此來校對本機(jī)時(shí)間。本文以C語言為工具,實(shí)現(xiàn)了一個(gè)簡單的在線對時(shí)器的開發(fā)。
關(guān)鍵詞:C語言 在線對時(shí)
中圖分類號(hào):TP302 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1672-3791(2012)10(b)-0006-01
在線對時(shí)器的作用是從Internet上獲取準(zhǔn)確的時(shí)間。它的基本設(shè)計(jì)思想是開發(fā)出客戶端工具,以此登錄到網(wǎng)絡(luò)上的授時(shí)服務(wù)器并獲取它的準(zhǔn)確時(shí)間,然后根據(jù)這個(gè)時(shí)間來校對本機(jī)的系統(tǒng)時(shí)間。下面以C語言為開發(fā)工具,介紹一種簡單的在線定時(shí)器的實(shí)現(xiàn)方法。
1 登錄到授時(shí)服務(wù)器
Internet上可用的授時(shí)服務(wù)器很多,這里采用香港的官方授時(shí)服務(wù)器(IP地址:210.0.235.14)。
核心代碼如下。
//初始化套接字
SOCKETsock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
SOCKADDR_INsa;
sa.sin_family=AF_INET;
//設(shè)置套接字連接服務(wù)器端的端口(客戶端端口由套接字動(dòng)態(tài)分配,無需指定)
sa.sin_port=htons(IPPORT_TIMESERVER);//IPPORT_TIMESERVER是宏,對應(yīng)的
//值是37,它代表TIMESERVER的端口號(hào)
//設(shè)置要連接到的授時(shí)服務(wù)器的IP地址
sa.sin_addr.S_un.S_addr=inet_addr("210.0.235.14");
//指定了端口號(hào)和IP地址之后,開始登錄到授時(shí)服務(wù)器
connect(sock,(SOCKADDR*)&sa,sizeof(sa));
2 接收授時(shí)服務(wù)器傳過來的信息
我們這里采用的授時(shí)服務(wù)器,返回給客戶端的是1900年1月1日0點(diǎn)0分0秒到現(xiàn)在的秒數(shù),是整型數(shù)字。而我們將要使用的接收服務(wù)器返回的消息的recv函數(shù),它相應(yīng)的參數(shù)是字符指針類型,因此需要進(jìn)行類型轉(zhuǎn)換,這在代碼中將得到體現(xiàn)。具體如下。
//定義用來接收返回的時(shí)間秒數(shù)的變量
unsignedlongulTime=0;
//使用recv函數(shù)接收以秒數(shù)代表的當(dāng)前時(shí)間
recv(sock,(char*)&ulTime,sizeof(unsignedlong),0);
那么這個(gè)秒數(shù)是多少呢?我們可以將它打印出來看一下:
//定義字符緩沖區(qū)
TCHARbuff[256];
//將緩沖區(qū)清零
ZeroMemory(buff,sizeof(buff)/sizeof(TCHAR));
將接收的秒數(shù)寫到定義的緩沖區(qū)中
wsprintf(buff,"%i",ulTime);
//以對話框的形式顯示接收的秒數(shù)
MessageBox(NULL,buff,TEXT("以秒數(shù)代表的當(dāng)前時(shí)間"),MB_OK);
我們得到的對話框如圖1所示。
為什么得到的結(jié)果明顯不對呢?這涉及到字節(jié)順序的問題,也就是說我們的客戶機(jī)存儲(chǔ)的整數(shù)的字節(jié)順序和授時(shí)服務(wù)器不一致,導(dǎo)致傳過來的ulTime沒有得到正確的還原。這個(gè)問題很好解決,我們在將ulTime寫到緩沖區(qū)之前,使用ntohl函數(shù)對ulTime做個(gè)處理即可(ulTime=ntohl(ulTime))。
3 將秒數(shù)表示的時(shí)間轉(zhuǎn)換為字符形式的時(shí)間
下面我們要將上面得到的一串?dāng)?shù)字轉(zhuǎn)換為我們看得懂的字符形式的時(shí)間,我們用以下代碼實(shí)現(xiàn)。
SYSTEMTIMEst;
UINT64uiCurTime,uiBaseTime,uiResult;
uiBaseTime=((UINT64)HIGHTIME<<32)+LOWTIME;
uiCurTime=(UINT64)ulTime*(UINT64)10000000;
uiResult=uiBaseTime+uiCurTime;
FileTimeToSystemTime((LPFILETIME)&uiResult,&st);
以上代碼將接收到的以ulTime代表的秒數(shù)轉(zhuǎn)換為了st這個(gè)結(jié)構(gòu)體變量所代表的字符形式的時(shí)間(st中包含了年、月、日、時(shí)、分、秒的信息)。
我們將st中的內(nèi)容打印出來看一下,用以下代碼實(shí)現(xiàn)。
TCHARbuff[256];
ZeroMemory(buff,sizeof(buff)/sizeof(TCHAR));
wsprintf(buff,TEXT("%i年%i月%i日%i:%i:%i"),st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);//中國時(shí)區(qū)在東八區(qū),因此在小時(shí)上加8;
MessageBox(NULL,buff,TEXT("字符形式的時(shí)間"),MB_OK);
打印出來的結(jié)果如圖2所示。
為什么得到的小時(shí)不對呢?很簡單,中國在東八區(qū),應(yīng)該在小時(shí)上加上8,也就是將st.wHour改為st.wHour+8。
4 將得到的時(shí)間設(shè)成本機(jī)系統(tǒng)時(shí)間
經(jīng)過以上的測試,我們已經(jīng)得到了授時(shí)服務(wù)器上的準(zhǔn)確時(shí)間。將這個(gè)時(shí)間設(shè)置成本地系統(tǒng)時(shí)間即可,代碼只需一句。
SetSystemTime(&st);//將st這個(gè)結(jié)構(gòu)體變量所對應(yīng)的時(shí)間賦給本機(jī)。
5 結(jié)語
本文介紹了用C語言實(shí)現(xiàn)的在線對時(shí)器開發(fā)的基本思路和核心代碼。用其它高級(jí)語言開發(fā)在線對時(shí)器的基本方法與此類似。希望這樣的客戶端工具的開發(fā),對于想深入學(xué)習(xí)網(wǎng)絡(luò)編程的朋友,能起到一個(gè)鋪墊的作用。
參考文獻(xiàn)
[1] 譚浩強(qiáng).C程序設(shè)計(jì)[M].清華大學(xué)出版社,1999.
[2] 佩措爾德.Windows程序設(shè)計(jì)[M].清華大學(xué)出版社,2010.