房好帥等
摘要:基于嵌入式ARM-Linux平臺,提出了一種Web服務(wù)器的設(shè)計方案與實(shí)現(xiàn)方法,采用Socket編程實(shí)現(xiàn)Http協(xié)議解析及網(wǎng)絡(luò)通信,設(shè)計了多進(jìn)程并發(fā)請求處理機(jī)制,支持html頁面和執(zhí)行CGI程序。在S3C2440硬件平臺上測試,能夠正確的響應(yīng)Http遠(yuǎn)程請求,可用于嵌入式設(shè)備的遠(yuǎn)程控制。
關(guān)鍵詞:Web服務(wù)器;Socket編程;Http請求;遠(yuǎn)程控制
中圖分類號:TP393 文獻(xiàn)標(biāo)識碼:A 文章編號:1009-3044(2014)10-2206-03
Abstract: Discusses the design proposal and implementation of Web server based on embedded ARM-Linux platform, Http data package analyzing and network communication are accomplished via socket programming, then put forward the mechanism for the multi-process concurrent request, can support HTML page and the execution of a CGI program. At last testing the implementation on the S3C2440 platform, the web server work well in responsing to the Http remote request, therefore can be used for remote control of embedded devices.
Key words: Web server; Socket programming; Http request; remote control
隨著嵌入式系統(tǒng)在工業(yè)現(xiàn)場、環(huán)境監(jiān)控等領(lǐng)域的應(yīng)用逐漸廣泛,越來越多的場合需要通過網(wǎng)絡(luò)對嵌入式設(shè)備進(jìn)行遠(yuǎn)程控制,因此在基于ARM-Linux平臺的解決方案中就需要設(shè)計適合于嵌入式設(shè)備的Web服務(wù)器。當(dāng)前比較成熟的Web服務(wù)器軟件如Apache、Nginx、Lighttpd等功能較為完備,占用資源也較多,適合在PC或服務(wù)器上運(yùn)行;比較精簡的Web服務(wù)器如Boa、thttpd等,運(yùn)行系統(tǒng)開銷較小,很多應(yīng)用場景中被移植到了嵌入式平臺,但一般實(shí)現(xiàn)為單進(jìn)程服務(wù)器,當(dāng)前用戶請求處理完成后才能響應(yīng)下一個用戶的請求,不具備并發(fā)處理功能。
針對當(dāng)前Web服務(wù)器存在的問題,該文提出一種適合于嵌入式平臺的實(shí)現(xiàn)方案,考慮到嵌入式平臺存在硬件資源限制,設(shè)計方案時考慮:1)功能實(shí)現(xiàn)精簡,支持html頁面請求和執(zhí)行CGI程序即可滿足遠(yuǎn)程控制的要求;2)能夠并發(fā)處理多個用戶的同時請求;3)Web服務(wù)器軟件交叉編譯后能夠穩(wěn)定運(yùn)行且占用資源少。
1 總體設(shè)計方案及流程分析
Web服務(wù)器在運(yùn)行期間通過Http協(xié)議與瀏覽器進(jìn)行通信,瀏覽器通過輸入URL地址或html form表單向Web服務(wù)器發(fā)出請求,Web服務(wù)器進(jìn)行解析Http協(xié)議數(shù)據(jù)包,提取請求文件信息與表單數(shù)據(jù),之后進(jìn)行處理相應(yīng),總體流程如圖1所示。
嵌入式Web服務(wù)器軟件實(shí)現(xiàn)采用Linux C編程,在PC上搭建ARM-Linux交叉開發(fā)環(huán)境,采用makefile文件進(jìn)行工程構(gòu)建管理,最后在S3C2440硬件平臺上測試。
2 功能模塊設(shè)計與實(shí)現(xiàn)
2.1 多進(jìn)程并發(fā)請求處理機(jī)制
文獻(xiàn)[4]提出了包括迭代服務(wù)器和并發(fā)服務(wù)器共9種服務(wù)器設(shè)計模型,這些模型來源于實(shí)際工程實(shí)踐,可作為本文項目實(shí)現(xiàn)的參考??紤]到需要處理用戶的并發(fā)請求,但并發(fā)請求的同時連接數(shù)較少,同時也要執(zhí)行CGI程序,故采用為每個客戶請求fork一個子進(jìn)程的并發(fā)服務(wù)器模型,其流程如下:
1)父進(jìn)程采用accept函數(shù)阻塞接收客戶的連接,當(dāng)有客戶請求發(fā)生時,該函數(shù)返回一個連接套接字connfd進(jìn)行與客戶通信;
2)父進(jìn)程采用fork系統(tǒng)調(diào)用為請求產(chǎn)生一個子進(jìn)程,由于子進(jìn)程與父進(jìn)程共享連接套接字connfd,故子進(jìn)程通過connfd獲取請求Http協(xié)議數(shù)據(jù)包,進(jìn)行解析后處理html請求或CGI請求,之后通過connfd發(fā)送響應(yīng)數(shù)據(jù)包,請求處理結(jié)束后關(guān)閉connfd。
3)父進(jìn)程需要關(guān)閉連接套接字connfd,將導(dǎo)致其描述符的引用計數(shù)減1,這樣保證了父進(jìn)程不會耗盡可用的描述符數(shù),另外當(dāng)子進(jìn)程關(guān)閉connfd時,描述符的計數(shù)為0,保證能夠正確的向客戶發(fā)送連接終止序列。
2.2 Http協(xié)議數(shù)據(jù)包請求解析
Http請求數(shù)據(jù)包由三部分組成:請求行、消息報頭、請求正文,請求行以一個方法符號開頭(GET或POST),之后是以空格分開請求的URI,GET方法對應(yīng)的URI通常還包括請求參數(shù),如/cgi-bin/testform.cgi?u_name=fang&u_password=3241;POST方法的請求參數(shù)的解析需要讀取請求正文中的Content-Length獲取請求參數(shù)字符串長度,之后跳過一個空行(只有CRLF的行)后可獲取請求參數(shù)。
2.3 處理html請求及響應(yīng)
若請求數(shù)據(jù)包經(jīng)過解析請求URL地址為html文件,對應(yīng)處理步驟如下:
1)檢查html存放路徑下是否有請求文件,若不存在返回404 Not Found;
2)若請求文件存在,讀取文件內(nèi)容;
3)通過connfd將文件內(nèi)容發(fā)送至請求客戶(瀏覽器),瀏覽器可以進(jìn)行解析顯示。
2.4 處理CGI請求及響應(yīng)
若請求數(shù)據(jù)包經(jīng)過解析為請求執(zhí)行CGI程序,首先將請求方法和參數(shù)穿遞給CGI程序,在子進(jìn)程中需要根據(jù)GET、POST兩種具體情況進(jìn)行處理。如果為GET方法提交參數(shù),其流程為:
1)設(shè)置環(huán)境變量REQUEST_METHOD為GET:
setenv("REQUEST_METHOD", "GET", 1);
2)設(shè)置環(huán)境變量QUERY_STRING,其值為參數(shù)字符串:
setenv("QUERY_STRING", parameters_string, 1);
如果為POST方法提交參數(shù),其流程為:
1)設(shè)置環(huán)境變量REQUEST_METHOD為POST:
setenv("REQUEST_METHOD", "POST", 1);
2)設(shè)置環(huán)境變量CONTENT_LENGTH,其值為參數(shù)字符串長度:
setenv("CONTENT_LENGTH", parameters_string_len, 1);
3)將參數(shù)字符串寫入標(biāo)準(zhǔn)輸入,需要將標(biāo)準(zhǔn)輸入先進(jìn)行重定向:
int file_pipes[2];
pipe(file_pipes);
close(0);//關(guān)閉進(jìn)程標(biāo)準(zhǔn)輸入
dup(file_pipes[0]);//重定向標(biāo)準(zhǔn)輸入
write(file_pipes[1], parameters_string, parameters_string_len);
由于CGI程序采用system系統(tǒng)調(diào)用產(chǎn)生一個新的子進(jìn)程進(jìn)行執(zhí)行,CGI程序的執(zhí)行結(jié)果要作為相應(yīng)信息發(fā)送給客戶,在本文設(shè)計的方案中將stdout重定向到一個臨時文件:
char temp_filename[] = "/tmp/temp_file.XXXXXX";
int fd = mkstemp(temp_filename);
unlink(temp_filename);
dup2(fd, fileno(stdout));
CGI程序作為子進(jìn)程執(zhí)行可繼承父進(jìn)程的環(huán)境變量與打開的文件描述符,故可以獲取請求參數(shù)字符串。執(zhí)行完畢后,讀取臨時文件內(nèi)容,將文件內(nèi)容加上http協(xié)議響應(yīng)頭,通過connfd發(fā)送至請求客戶(瀏覽器)。
2.5 防止僵尸進(jìn)程的形成
由于父進(jìn)程采用fork為每個請求產(chǎn)生一個子進(jìn)程,當(dāng)請求響應(yīng)后子進(jìn)程結(jié)束,故需要在父進(jìn)程中需要通過調(diào)用wait或waitpid等待取得子進(jìn)程的終止?fàn)顟B(tài),避免子進(jìn)程形成僵尸進(jìn)程。另外父進(jìn)程還要負(fù)責(zé)接收客戶的連接,故不能在父進(jìn)程中采用wait或waitpid阻塞等待子進(jìn)程終止,這樣會影響并發(fā)響應(yīng)。在本文的方案中,采用異步信號的方法防止子進(jìn)程形成僵尸進(jìn)程,具體實(shí)現(xiàn)方法和原理如下:
1)當(dāng)子進(jìn)程終止時,子進(jìn)程會向父進(jìn)程發(fā)送SIGCHLD信號;
2)父進(jìn)程中,設(shè)置SIGCHLD信號處理函數(shù)sigchld_handler進(jìn)行捕:
signal(SIGCHLD, sigchld_handler);
3)在sigchld_handler中進(jìn)行waitpid等待:
void sigchld_handler (int signo) {
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) >0);
}
由于SIGCHLD為不可靠信號,內(nèi)核不會對多個信號產(chǎn)生進(jìn)行排隊,故waitpid系統(tǒng)調(diào)用需要采用WNOHANG參數(shù),這樣在有尚未終止的子進(jìn)程運(yùn)行時不會阻塞。
3 在嵌入式平臺上測試
3.1 測試環(huán)境與案例
采用天嵌公司的S3C2440開發(fā)板進(jìn)行測試,Web服務(wù)器經(jīng)過arm-linux-gcc交叉編譯運(yùn)行于嵌入式平臺;CGI程序支持GET、POST兩種請求方法,獲取點(diǎn)亮的LED序號和操作方式(點(diǎn)亮、熄滅),之后控制LED,實(shí)現(xiàn)基于Web的遠(yuǎn)程控制,流程如圖2所示。
編寫一測試html文件,內(nèi)容包括兩個form表單,分別測試GET和POST方法,提交的參數(shù)格式為:control_type=%s&led_no=%d。
3.2 測試結(jié)果
經(jīng)過測試,html文件內(nèi)容可以正確的顯示在瀏覽器中,GET和POST方法都可以正確的將請求參數(shù)提交到CGI程序;同時進(jìn)行多個請求沒有出現(xiàn)阻塞或是拒絕服務(wù)的情況;另外采用ps命令查看進(jìn)程,沒有發(fā)現(xiàn)產(chǎn)生僵尸進(jìn)程的產(chǎn)生,說明3.5提出的方法有效;通過/proc/PID/fd及l(fā)sof命令的方法查看父進(jìn)程的打開的socket描述符,發(fā)現(xiàn)都能夠正確的關(guān)閉,因此本W(wǎng)eb服務(wù)器可以穩(wěn)定的長期運(yùn)行。
4 結(jié)束語與展望
本文針對ARM-Linux平臺,提出了一種嵌入式Web服務(wù)器實(shí)現(xiàn)方法,解決了當(dāng)前已有Web服務(wù)器存在的不能處理并發(fā)請求的問題,同時功能精簡實(shí)用,配置運(yùn)行方法簡單,經(jīng)過實(shí)際測試,能夠滿足嵌入式平臺遠(yuǎn)程控制中應(yīng)用要求。
參考文獻(xiàn):
[1] 戴麗華.嵌入式Web服務(wù)器的研究和應(yīng)用[J].輕工科技,2013(11):72-74.
[2] 王毅.探析嵌入式Web服務(wù)器的設(shè)計與實(shí)現(xiàn)[J].電子世界,2013(12):17-18.
[3] 王俊,郭書軍.嵌入式Web服務(wù)器的實(shí)現(xiàn)及其CGI應(yīng)用[J].電子設(shè)計工程,2011,19(21):152-155.
[4] W Richard S.UNIX網(wǎng)絡(luò)編程[M].北京:人民郵電出版社,2010.
[5] 宋凱,嚴(yán)麗平,甘嵐.嵌入式Web服務(wù)器的設(shè)計與實(shí)現(xiàn)[J].計算機(jī)工程與設(shè)計,2009,30(4):808-810.
[6] 謝仕義,徐兵.嵌入式Web服務(wù)器的設(shè)計及其CGI實(shí)現(xiàn)[J].計算機(jī)工程與設(shè)計,2007,28(7):1598-1601.