DS80C400的Keil C語(yǔ)言編程
SolarWinds為Windows (平臺(tái)提供了一個(gè)免費(fèi)的TFTP服務(wù)器,它被應(yīng)用于該演示程序的開發(fā)中。在SolarWinds網(wǎng)站(www.solarwinds.net),跟隨Downloads - Free Software菜單可找到TFTP服務(wù)器下載。安裝以后,使用File菜單下的Configure選項(xiàng)來(lái)配置現(xiàn)有文件。確保程序使用你的TFTP服務(wù)器IP地址(TFTP_IP_MSP, TFTP_IP_2,TFTP_IP_3和TFTP_IP_LSB)。
簡(jiǎn)單的HTTP服務(wù)器
該應(yīng)用中的HTTP服務(wù)器是RFC 2068所描述的HTTP服務(wù)器的一個(gè)簡(jiǎn)化版實(shí)現(xiàn)。在該版本下,只支持'GET'方法。輸入頭被忽略,只給出很少的輸出頭。
服務(wù)器套接字通過(guò)調(diào)用Berkley型套接字函數(shù)來(lái)創(chuàng)建,這樣使得服務(wù)器套接字容易建立。以下代碼說(shuō)明了這個(gè)簡(jiǎn)單的HTTP服務(wù)器是如何創(chuàng)建、邦定并接受新連接的。
struct sockaddr local;unsigned int socket_handle, new_socket_handle, temp;socket_handle = socket(0, SOCKET_TYPE_STREAM, 0);local.sin_port = 80;bind(socket_handle, local, sizeof(local));listen(socket_handle, 5);printf("Ready to accept HTTP connections...r");// here is the main loop of the HTTP serverwhile (1){new_socket_handle = accept(socket_handle, address, sizeof(address));handleRequest(new_socket_handle);closesocket(new_socket_handle);}請(qǐng)注意,接受了新的套接字后,這個(gè)簡(jiǎn)單的應(yīng)用并不啟動(dòng)新的線程或進(jìn)程來(lái)處理請(qǐng)求。而是在同一進(jìn)程中處理該請(qǐng)求。任何非演示版的HTTP服務(wù)器都會(huì)在新的線程中處理收到的請(qǐng)求,這樣就允許多個(gè)連接出現(xiàn)并被同時(shí)處理。請(qǐng)求處理完后,關(guān)閉套接字,等待另一個(gè)收到的連接。
handleRequest方法從收到的請(qǐng)求中解析出一個(gè)文件名,并確定該方法是'GET'。其它方法(甚至是'POST','HEAD'或'OPTIONS')均不被接受。兩個(gè)文件名被作為特例處理。當(dāng)請(qǐng)求文件為time.html時(shí),服務(wù)器動(dòng)態(tài)產(chǎn)生一個(gè)響應(yīng),其中包含來(lái)自timeserver的最新結(jié)果,以及自上一次查詢時(shí)間服務(wù)器以來(lái)的秒數(shù)。當(dāng)請(qǐng)求文件為stats.html時(shí),將顯示服務(wù)器的正常運(yùn)行時(shí)間和請(qǐng)求次數(shù)統(tǒng)計(jì)結(jié)果。
如果找不到文件或發(fā)出的是無(wú)效的請(qǐng)求方法,HTTP服務(wù)器報(bào)告錯(cuò)誤碼。
SNTP客戶端
第二個(gè)主要部分是Simple Network Time Protocol客戶端,參見RFC 1361的描述。它是Network Time Protocol (RFC 1305)的一個(gè)版本。SNTP要求UDP從一個(gè)偵聽端口123的服務(wù)器請(qǐng)求時(shí)戳。我們的timeserver使用以下代碼周期性地與服務(wù)器time.nist.gov同步。請(qǐng)注意,在寫這篇文章時(shí),DNS檢索還不被支持,因此服務(wù)器的IP地址須手動(dòng)設(shè)置。DNS現(xiàn)已被添加到了C庫(kù)網(wǎng)站,以下代碼更新后可通過(guò)檢索獲得IP地址。
socket_handle = socket(0, SOCKET_TYPE_DATAGRAM, 0);// set a timeout of about 2 secondsbuffer[0] = 0x0;buffer[1] = 0x0;buffer[2] = 0x8;buffer[3] = 0x0;setsockopt(socket_handle, 0, SO_TIMEOUT, buffer, 200);buffer[2] = 0; // reset since we used this in call to setsockoptbuffer[0] = 0x23; // No warning/NTP Ver 4/Clientaddress.sin_addr[12] = TIME_NIST_GOV_IP_MSB;address.sin_addr[13] = TIME_NIST_GOV_IP_2;address.sin_addr[14] = TIME_NIST_GOV_IP_3;address.sin_addr[15] = TIME_NIST_GOV_IP_LSB;address.sin_port = NTP_PORT;sendto(socket_handle, buffer, 48, 0, address, sizeof(struct sockaddr));recvfrom(socket_handle, buffer, 256, 0, address, sizeof(struct sockaddr));timeStamp = *(unsigned long*)(buffer[40]);timeStamp = timeStamp - NTP_UNIX_TIME_OFFSET;// now we have time since Jan 1 1970formatTimeString(timeStamp, "London", last_time_reading_1);last_reading_seconds = getTimeSeconds();closesocket(socket_handle);首先生成一個(gè)數(shù)據(jù)報(bào)套接字,并給定一個(gè)約2秒的超時(shí)(0x800==2048ms)。這樣可以確保在與我們選擇的服務(wù)器通信失敗時(shí),不必?zé)o限期地等待下去。
下一行設(shè)定請(qǐng)求選項(xiàng)。關(guān)于這些位的描述參見RFC 1361第三節(jié)。值0x23要求閏秒時(shí)無(wú)需告警,要求采用NTP版本4,并聲明模式為'Client'。當(dāng)我們使用公共數(shù)據(jù)報(bào)函數(shù)sendto和recvfrom發(fā)出請(qǐng)求并收到回答后,時(shí)戳的秒部被賦給變量timeStamp,然后調(diào)整到參考時(shí)間1970年1月1日。formatTimeString函數(shù)將時(shí)戳轉(zhuǎn)換為易讀的字符串,如“In London it is 15:37:37 on March 31, 2003”。
getTimeSeconds函數(shù)以DS80C400內(nèi)部時(shí)鐘為基礎(chǔ)確定上一次更新。由于該程序大約每60秒才更新一次,HTML頁(yè)time.html使用這個(gè)數(shù)值來(lái)報(bào)告自上次更新以來(lái)的時(shí)間間隔。最后,關(guān)閉套接字,SNTP客戶端在下面的60秒內(nèi)進(jìn)入休眠。
有關(guān)同步的說(shuō)明
在LARGE存儲(chǔ)模式下,Keil編譯器將通過(guò)在進(jìn)程交換中非安全的存儲(chǔ)器傳遞有限數(shù)量的參數(shù)。這就意味著有些函數(shù)不能由多個(gè)程序同時(shí)調(diào)用。盡管已專為 400開發(fā)了C庫(kù),其中的所有變量都通過(guò)在進(jìn)程交換中安全的直接存儲(chǔ)器傳遞,有些函數(shù)仍然是危險(xiǎn)的。例如,Berkeley式的套接字header要求一些較長(zhǎng)的方法簽名,它會(huì)涉及到一些通過(guò)非安全存儲(chǔ)器傳遞的數(shù)據(jù)。因此,針對(duì)套接字有兩個(gè)庫(kù):
一個(gè)庫(kù)(rom_sock.lib)遵循Berkeley式的header。但是,兩個(gè)進(jìn)程同時(shí)用這個(gè)庫(kù)調(diào)用某個(gè)函數(shù)是不安全的。不過(guò),如果一個(gè)進(jìn)程正在使用UDP函數(shù)而另一個(gè)正在使用TCP函數(shù)就不會(huì)有問(wèn)題。為了對(duì)并發(fā)訪問(wèn)非安全存儲(chǔ)器提供真正的保護(hù),開發(fā)了另外一個(gè)套接字庫(kù)(rom_sock.lib)。該庫(kù)中的函數(shù)類似于Berkeley型函數(shù),但具有更少或重新安排的變量,以使Keil編譯器通過(guò)安全存儲(chǔ)區(qū)傳遞參數(shù)。無(wú)論何種情況,請(qǐng)參考相關(guān)文檔,以確認(rèn)函數(shù)是否為多進(jìn)程安全的。
c語(yǔ)言相關(guān)文章:c語(yǔ)言教程
評(píng)論