嵌入式WEB服務(wù)器常見的有
lighttpd
shttpd
thttpd
boa
mathopd
minihttpd
appweb
goahead
========================================================================
嵌入式WEB服務(wù)器BOA的移植方法(一)2007-2-26 16:20:00
隨著Internet技術(shù)的興起,在嵌入式設(shè)備的管理與交互中,基于Web方式的應(yīng)用成為目前的主流,
這種程序結(jié)構(gòu)也就是大家非常熟悉的B/S結(jié)構(gòu),即在 嵌入式設(shè)備上運(yùn)行一個(gè)支持腳本或CGI功能的Web服務(wù)器,
能夠生成動(dòng)態(tài)頁(yè)面,在用戶端只需要通過(guò)Web瀏覽器就可以對(duì)嵌入式設(shè)備進(jìn)行管理和監(jiān)控,非常方 便實(shí)用。
本節(jié)主要介紹這種應(yīng)用的開發(fā)和移植工作。
用戶首先需要在嵌入式設(shè)備上成功移植支持腳本或CGI功能的Web服務(wù)器,然后才能進(jìn)行應(yīng)用程序的開發(fā)。
1、 嵌入式Web服務(wù)器移植 由于嵌入式設(shè)備資源一般都比較有限,并且也不需要能同時(shí)處理很多用戶的請(qǐng)求,
因此不會(huì)使用Linux下最常用的如Apache 等服務(wù)器,而需要使用一些專門為嵌入式設(shè)備設(shè)計(jì)的Web服務(wù)器,
這些Web服務(wù)器在存貯空間和運(yùn)行時(shí)所占有的內(nèi)存空間上都會(huì)非常適合于嵌入式應(yīng)用場(chǎng)合。
典型的嵌入式Web服務(wù)器有Boa (www.boa.org)和thttpd (http://www.acme.com/software/thttpd/)等,
它們和Apache等高性能的Web服務(wù)器主要的區(qū)別在于它們一般是單進(jìn)程服務(wù)器,只有在完成一個(gè)用戶請(qǐng)求后才能響應(yīng)
另一個(gè)用戶的請(qǐng)求,而無(wú)法并發(fā)響應(yīng),但這在嵌入式設(shè)備的應(yīng)用場(chǎng)合里已經(jīng)足夠了。
我們紹比較常用的Boa服務(wù)器的移植。
Boa是一個(gè)非常小巧的Web服務(wù)器,可執(zhí)行代碼只有約60KB。它是一個(gè)單任務(wù)Web服務(wù)器,只能依次完成用戶的請(qǐng)求,
而不會(huì)fork出新的進(jìn)程來(lái)處理 并發(fā)連接請(qǐng)求。但Boa支持CGI,能夠?yàn)?span lang="EN-US">CGI程序fork出一個(gè)進(jìn)程來(lái)執(zhí)行。Boa的設(shè)計(jì)目標(biāo)
是速度和安全,在其站點(diǎn)公布的性能測(cè)試中,Boa的性能 要好于Apache服務(wù)器。
第一步完成Boa程序的移植。從www.boa.org下載Boa源碼,當(dāng)前最新版本為0.94.13,將其解壓并進(jìn)入源碼目錄的src
子目錄
# tar xzf boa-0.94.13.tar.gz
# cd boa-0.94.13/src
生成Makefile文件
# ./configure
修改Makefile文件,找到CC=gcc,將其改成CC = arm-linux-gcc,再找到CPP = gcc –E,
將其改成CPP = arm-linux-gcc –E,并保存退出。
然后運(yùn)行make進(jìn)行編譯,得到的可執(zhí)行程序?yàn)?span lang="EN-US">boa,將調(diào)試信息剝?nèi)ィ玫降淖詈蟪绦蛑挥屑s60KB大小。
# make
# arm-linux-strip boa
第二步完成Boa的配置,使其能夠支持CGI程序的執(zhí)行。Boa需要在/etc目錄下建立一個(gè)boa目錄,里面放入Boa的主要
配置文件boa.conf。在Boa源碼目錄下已有一個(gè)示例boa.conf,可以在其基礎(chǔ)上進(jìn)行修改,下面解釋一下該文件的含義:
#監(jiān)聽的端口號(hào),缺省都是80,一般無(wú)需修改
Port 80
# bind調(diào)用的IP地址,一般注釋掉,表明綁定到INADDR_ANY,通配于服務(wù)器的所有IP地址
#Listen 192.68.0.5
#作為哪個(gè)用戶運(yùn)行,即它擁有該用戶的權(quán)限,一般都是nobody,需要/etc/passwd中有
#nobody用戶
User nobody
#作為哪個(gè)用戶組運(yùn)行,即它擁有該用戶組的權(quán)限,一般都是nogroup,需要在/etc/group文
#件中有nogroup組
Group nogroup
#當(dāng)服務(wù)器發(fā)生問(wèn)題時(shí)發(fā)送報(bào)警的email地址,目前未用,注釋掉
#ServerAdmin root@localhost
#錯(cuò)誤日志文件。如果沒(méi)有以/開始,則表示從服務(wù)器的根路徑開始。如果不需要錯(cuò)誤日志,
則用#/dev/null。在下面設(shè)置時(shí),注意一定要建立/var/log/boa目錄
ErrorLog /var/log/boa/error_log
#訪問(wèn)日志文件。如果沒(méi)有以/開始,則表示從服務(wù)器的根路徑開始。如果不需要錯(cuò)誤日志,
則用#/dev/null或直接注釋掉。在下面設(shè)置時(shí),注意一定要建立/var/log/boa目錄
#AccessLog /var/log/boa/access_log
#是否使用本地時(shí)間。如果沒(méi)有注釋掉,則使用本地時(shí)間。注釋掉則使用UTC時(shí)間
#UseLocaltime
#是否記錄CGI運(yùn)行信息,如果沒(méi)有注釋掉,則記錄,注釋掉則不記錄
#VerboseCGILogs
#服務(wù)器名字
ServerName www.hyesco.com
#是否啟動(dòng)虛擬主機(jī)功能,即設(shè)備可以有多個(gè)網(wǎng)絡(luò)接口,每個(gè)接口都可以擁有一個(gè)虛擬的Web服
#務(wù)器。一般注釋掉,即不需要啟動(dòng)
#VirtualHost
#非常重要,HTML文檔的主目錄。如果沒(méi)有以/開始,則表示從服務(wù)器的根路徑開始。
DocumentRoot /var/www
#如果收到一個(gè)用戶請(qǐng)求的話,在用戶主目錄后再增加的目錄名
UserDir public_html
#HTML目錄索引的文件名,也是沒(méi)有用戶只指明訪問(wèn)目錄時(shí)返回的文件名
DirectoryIndex index.html
#當(dāng)HTML目錄沒(méi)有索引文件時(shí),用戶只指明訪問(wèn)目錄時(shí),boa會(huì)調(diào)用該程序生成索引文件然后
#返回給用戶,因?yàn)樵撨^(guò)程比較慢最好不執(zhí)行,可以注釋掉或者給每個(gè)HTML目錄加上#DirectoryIndex指明的文件
#DirectoryMaker /usr/lib/boa/boa_indexer
#如果DirectoryIndex不存在,并且DirectoryMaker被注釋,那么就用Boa自帶的索引
#生成程序來(lái)生成目錄的索引文件并輸出到下面目錄,該目錄必須是Boa能讀寫
# DirectoryCache /var/spool/boa/dircache
#一個(gè)連接所允許的HTTP持續(xù)作用請(qǐng)求最大數(shù)目,注釋或設(shè)為0都將關(guān)閉HTTP持續(xù)作用
KeepAliveMax 1000
#HTTP持續(xù)作用中服務(wù)器在兩次請(qǐng)求之間等待的時(shí)間數(shù),以秒為單位,超時(shí)將關(guān)閉連接
KeepAliveTimeout 10
#指明mime.types文件位置。如果沒(méi)有以/開始,則表示從服務(wù)器的根路徑開始。可以注釋掉
#避免使用mime.types文件,此時(shí)需要用AddType在本文件里指明
MimeTypes /etc/mime.types
#文件擴(kuò)展名沒(méi)有或未知的話,使用的缺省MIME類型
DefaultType text/plain
#提供CGI程序的PATH環(huán)境變量值
CGIPath /bin:/usr/bin:/usr/local/bin
#將文件擴(kuò)展名和MIME類型關(guān)聯(lián)起來(lái),和mime.types文件作用一樣。如果用mime.types
#文件,則注釋掉,如果不使用mime.types文件,則必須使用
#AddType application/x-httpd-cgi cgi
#指明文檔重定向路徑
#Redirect /bar http://elsewhere/feh/bar
#為路徑加上別名
Alias /doc /usr/doc
#非常重要,指明CGI腳本的虛擬路徑對(duì)應(yīng)的實(shí)際路徑。一般所有的CGI腳本都要放在實(shí)際路徑
#里,用戶訪問(wèn)執(zhí)行時(shí)輸入站點(diǎn)+虛擬路徑+CGI腳本名
ScriptAlias /cgi-bin/ /var/www/cgi-bin/
用戶可以根據(jù)自己需要,對(duì)boa.conf進(jìn)行修改,但必須要保證其他的輔助文件和設(shè)置必須和boa.conf里的配置相符,
不然Boa就不能正常工作。 在上面的例子中,我們還需要?jiǎng)?chuàng)建日志文件所在目錄/var/log/boa,
創(chuàng)建HTML文檔的主目錄/var/www,將mime.types文件拷貝 到/etc目錄,
創(chuàng)建CGI腳本所在目錄/var/www/cgi-bin/。mime.types文件用來(lái)指明不同文件擴(kuò)展名對(duì)應(yīng)的MIME類型,
一般 可以直接從Linux主機(jī)上拷貝一個(gè),大部分也都是在主機(jī)的/etc目錄下。
===================================================================
===================host test=======================================
1.進(jìn)入 boa-0.94.13/src
./configure
make
2.在etc/下建立boa目錄并將boa.conf拷貝到該目錄下.更改boa.conf
Group nogroup ===》Group 0
3.在 /var/log/下建立boa目錄,該目錄下可以查看boa服務(wù)器的日志
4.其它的一些路徑
默認(rèn)是/var/www下的內(nèi)容可以訪問(wèn) (DocumentRoot /var/www)
默認(rèn)cgi :ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ (cgi可執(zhí)行程序放在 /usr/lib/cgi-bin/目錄下)
例子http://201.201.201.249/cgi-bin/cgi-test.cgi
CGIPath /bin:/usr/bin:/usr/local/bin
只有這些目錄下的命令可以被調(diào)用,如果要root的權(quán)限(如ifconfig配置ip)需要加上/sbin
下面舉個(gè)具體點(diǎn)的例子:
首先編譯pass.c,生成pass.cgi,把他放到/usr/lib/cgi-bin/目錄下
接著把pass.html放在/var/www下,當(dāng)然可以按照上面講的,把默認(rèn)訪問(wèn)的設(shè)置為pass.c。
下面就可以打開了。
注意:pass.html對(duì)應(yīng)的cgike可執(zhí)行文件是pass.cgi
=====================================================================
cgi例子
=====================================================================
//pass.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getcgidata(FILE* fp, char* requestmethod);
int main()
{
char *input;
char *req_method;
char name[64];
char pass[64];
int i = 0;
int j = 0;
// printf("Content-type: text/plain; charset=iso-8859-1\n\n");
printf("Content-type: text/html\n\n");
printf("The following is query reuslt:<br><br>");
req_method = getenv("REQUEST_METHOD");
input = getcgidata(stdin, req_method);
// 我們獲取的input字符串可能像如下的形式
// Username="admin"&Password="aaaaa"
// 其中"Username="和"&Password="都是固定的
// 而"admin"和"aaaaa"都是變化的,也是我們要獲取的
// 前面9個(gè)字符是UserName=
// 在"UserName="和"&"之間的是我們要取出來(lái)的用戶名
for ( i = 9; i < (int)strlen(input); i++ )
{
if ( input[i] == '&' )
{
name[j] = '\0';
break;
}
name[j++] = input[i];
}
// 前面9個(gè)字符 + "&Password="10個(gè)字符 + Username的字符數(shù)
// 是我們不要的,故省略掉,不拷貝
for ( i = 19 + strlen(name), j = 0; i < (int)strlen(input); i++ )
{
pass[j++] = input[i];
}
pass[j] = '\0';
printf("Your Username is %s<br>Your Password is %s<br> \n", name, pass);
return 0;
}
char* getcgidata(FILE* fp, char* requestmethod)
{
char* input;
int len;
int size = 1024;
int i = 0;
if (!strcmp(requestmethod, "GET"))
{
input = getenv("QUERY_STRING");
return input;
}
else if (!strcmp(requestmethod, "POST"))
{
len = atoi(getenv("CONTENT_LENGTH"));
input = (char*)malloc(sizeof(char)*(size + 1));
if (len == 0)
{
input[0] = '\0';
return input;
}
while(1)
{
input[i] = (char)fgetc(fp);
if (i == size)
{
input[i+1] = '\0';
return input;
}
--len;
if (feof(fp) || (!(len)))
{
i++;
input[i] = '\0';
return input;
}
i++;
}
}
return NULL;
}
/*
* gcc -o pass.cgi pass.c
*/
//pass.html
<html>
<head><title>用戶登陸驗(yàn)證</title></head>
<body>
<form name="form1" action="/cgi-bin/pass.cgi" method="POST">
<table align="center">
<tr><td align="center" colspan="2"></td></tr>
<tr>
<td align="right">用戶名</td>
<td><input type="text" name="Username"></td>
</tr>
<tr>
<td align="right">密 碼</td>
<td><input type="password" name="Password"></td>
</tr>
<tr>
<td><input type="submit" value="登 錄"></td>
<td><input type="reset" value="取 消"></td>
</tr>
</table>
</form>
</body>
</html>