http://www.cnblogs.com/bryce/archive/2011/05/23/2054435.html
嵌入式WEB服务器BOA和CGI
嵌入式WEB服务器常见的有
lighttpd
shttpd
thttpd
boa
mathopd
minihttpd
appweb
goahead
========================================================================
嵌入式WEB服务器BOA的移植方法(一)2007-2-26 16:20:00
随着Internet技术的兴起,在嵌入式设备的管理与交互中,基于Web方式的应用成为目前的主流,
这种程序结构也就是大家非常熟悉的B/S结构【C/S又称Client/Server或客户/服务器模式。B/S是Brower/Server的缩写,客户机上只要安装一个浏览器(Browser),B/S最大的优点就是可以在任何地方进行操作而不用安装任何专门的软件。】,即在 嵌入式设备上运行一个支持脚本或CGI功能的Web服务器,能够生成动态页面,在用户端只需要通过Web浏览器就可以对嵌入式设备进行管理和监控,非常方 便实用。
本节主要介绍这种应用的开发和移植工作。
用户首先需要在嵌入式设备上成功移植支持脚本或CGI功能的Web服务器,然后才能进行应用程序的开发。
1、 嵌入式Web服务器移植 由于嵌入式设备资源一般都比较有限,并且也不需要能同时处理很多用户的请求,
因此不会使用Linux下最常用的如Apache 等服务器,而需要使用一些专门为嵌入式设备设计的Web服务器,
这些Web服务器在存贮空间和运行时所占有的内存空间上都会非常适合于嵌入式应用场合。
典型的嵌入式Web服务器有Boa (www.boa.org)和thttpd (http://www.acme.com/software/thttpd/)等,
它们和Apache等高性能的Web服务器主要的区别在于它们一般是 单进程服务器,只有在完成一个用户请求后才能响应
另一个用户的请求,而无法并发响应,但这在嵌入式设备的应用场合里已经足够了。
我们绍比较常用的Boa服务器的移植。
Boa是一个非常小巧的Web服务器,可执行代码只有约60KB。它是一个单任务Web服务器,只能依次完成用户的请求,
而不会fork出新的进程来处理 并发连接请求。但Boa支持CGI,能够为CGI程序fork出一个进程来执行。Boa的设计目标
是速度和安全,在其站点公布的性能测试中,Boa的性能 要好于Apache服务器。
第一步完成Boa程序的移植。从www.boa.org下载Boa源码,当前最新版本为0.94.13,将其解压并进入源码目录的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,并保存退出。
然后运行make进行编译,得到的可执行程序为boa,将调试信息剥去,得到的最后程序只有约60KB大小。
# make
# arm-linux-strip boa
第二步完成Boa的配置,使其能够支持CGI程序的执行。Boa需要在/etc目录下建立一个boa目录,里面放入Boa的主要配置文件boa.conf。在Boa源码目录下已有一个示例boa.conf,可以在其基础上进行修改,下面解释一下该文件的含义:
#监听的端口号,缺省都是80,一般无需修改
Port 80
# bind调用的IP地址,一般注释掉,表明绑定到INADDR_ANY,通配于服务器的所有IP地址
#Listen 192.68.0.5
#作为哪个用户运行,即它拥有该用户的权限,一般都是nobody,需要/etc/passwd中有
#nobody用户
User nobody
#作为哪个用户组运行,即它拥有该用户组的权限,一般都是nogroup,需要在/etc/group文
#件中有nogroup组
Group nogroup
#当服务器发生问题时发送报警的email地址,目前未用,注释掉
#ServerAdmin root@localhost
#错误日志文件。如果没有以/开始,则表示从服务器的根路径开始。如果不需要错误日志,
则用#/dev/null。在下面设置时,注意一定要建立/var/log/boa目录
ErrorLog /var/log/boa/error_log
#访问日志文件。如果没有以/开始,则表示从服务器的根路径开始。如果不需要错误日志,
则用#/dev/null或直接注释掉。在下面设置时,注意一定要建立/var/log/boa目录
#AccessLog /var/log/boa/access_log
#是否使用本地时间。如果没有注释掉,则使用本地时间。注释掉则使用UTC时间
#UseLocaltime
#是否记录CGI运行信息,如果没有注释掉,则记录,注释掉则不记录
#VerboseCGILogs
#服务器名字
ServerName www.hyesco.com
#是否启动虚拟主机功能,即设备可以有多个网络接口,每个接口都可以拥有一个虚拟的Web服
#务器。一般注释掉,即不需要启动
#VirtualHost
#非常重要,HTML文档的主目录。如果没有以/开始,则表示从服务器的根路径开始。
DocumentRoot /var/www
#如果收到一个用户请求的话,在用户主目录后再增加的目录名
UserDir public_html
#HTML目录索引的文件名,也是没有用户只指明访问目录时返回的文件名
DirectoryIndex index.html
#当HTML目录没有索引文件时,用户只指明访问目录时,boa会调用该程序生成索引文件然后
#返回给用户,因为该过程比较慢最好不执行,可以注释掉或者给每个HTML目录加上#DirectoryIndex指明的文件
#DirectoryMaker /usr/lib/boa/boa_indexer
#如果DirectoryIndex不存在,并且DirectoryMaker被注释,那么就用Boa自带的索引
#生成程序来生成目录的索引文件并输出到下面目录,该目录必须是Boa能读写
# DirectoryCache /var/spool/boa/dircache
#一个连接所允许的HTTP持续作用请求最大数目,注释或设为0都将关闭HTTP持续作用
KeepAliveMax 1000
#HTTP持续作用中服务器在两次请求之间等待的时间数,以秒为单位,超时将关闭连接
KeepAliveTimeout 10
#指明mime.types文件位置。如果没有以/开始,则表示从服务器的根路径开始。可以注释掉
#避免使用mime.types文件,此时需要用AddType在本文件里指明
MimeTypes /etc/mime.types
#文件扩展名没有或未知的话,使用的缺省MIME类型
DefaultType text/plain
#提供CGI程序的PATH环境变量值
CGIPath /bin:/usr/bin:/usr/local/bin
#将文件扩展名和MIME类型关联起来,和mime.types文件作用一样。如果用mime.types
#文件,则注释掉,如果不使用mime.types文件,则必须使用
#AddType application/x-httpd-cgi cgi
#指明文档重定向路径
#Redirect /bar http://elsewhere/feh/bar
#为路径加上别名
Alias /doc /usr/doc
#非常重要,指明CGI脚本的虚拟路径对应的实际路径。一般所有的CGI脚本都要放在实际路径
#里,用户访问执行时输入站点+虚拟路径+CGI脚本名
ScriptAlias /cgi-bin/ /var/www/cgi-bin/
用户可以根据自己需要,对boa.conf进行修改,但必须要保证其他的辅助文件和设置必须和boa.conf里的配置相符,
不然Boa就不能正常工作。 在上面的例子中,我们还需要创建日志文件所在目录/var/log/boa,
创建HTML文档的主目录/var/www,将mime.types文件拷贝 到/etc目录,
创建CGI脚本所在目录/var/www/cgi-bin/。mime.types文件用来指明不同文件扩展名对应的MIME类型,
一般 可以直接从Linux主机上拷贝一个,大部分也都是在主机的/etc目录下。
还可以参考:
本文将对Boa服务器的配置文件boa.conf进行一下解释:
注:本文采用的Boa的版本是:boa-0.94.14rc21.tar.gz (最新版本,网上用的比较多的是boa-0.94.13)
其boa.conf在文件夹里:contrib/rpm/boa.conf
指定boa的日志目录
boa有两种日志文件:记录其所出现的错误和记录其运行状态。
1)记录其所出现的错误。ErrorLog /var/log/boa/error_log
2)记录其运行状态。AccessLog /var/log/boa/access_log
指定网页所在的目录
如:DocumentRoot /home/httpd/html
表示网页文件需放在此目录下。
默认的主页名
如:DirectoryIndex index.html
表示默认的主页名为 index.html
指定cgi 脚本的目录
如:ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/
boa.conf完整内容见下:
1. # Boa v0.94 configuration file 2. # File format has not changed from 0.93 3. # File format has changed little from 0.92 4. # version changes are noted in the comments 5. # 6. # The Boa configuration file is parsed with a lex/yacc or flex/bison 7. # generated parser. If it reports an error, the line number will be 8. # provided; it should be easy to spot. The syntax of each of these 9. # rules is very simple, and they can occur in any order. Where possible 10. # these directives mimic those of NCSA httpd 1.3; I saw no reason to 11. # introduce gratuitous differences. 12. 13. # $Id: boa.conf,v 1.2 2001/09/25 03:28:31 jnelson Exp $ 14. 15. # The "ServerRoot" is not in this configuration file. It can be compiled 16. # into the server (see defines.h) or specified on the command line with 17. # the -c option, for example: 18. # 19. # boa -c /usr/local/boa 20. 21. 22. # Port: The port Boa runs on. The default port for http servers is 80. 23. # If it is less than 1024, the server must be started as root. 24. 25. Port 80 26. 27. # Listen: the Internet address to bind(2) to. If you leave it out, 28. # it takes the behavior before 0.93.17.2, which is to bind to all 29. # addresses (INADDR_ANY). You only get one "Listen" directive, 30. # if you want service on multiple IP addresses, you have three choices: 31. # 1. Run boa without a "Listen" directive 32. # a. All addresses are treated the same; makes sense if the addresses 33. # are localhost, ppp, and eth0. 34. # b. Use the VirtualHost directive below to point requests to different 35. # files. Should be good for a very large number of addresses (web 36. # hosting clients). 37. # 2. Run one copy of boa per IP address, each has its own configuration 38. # with a "Listen" directive. No big deal up to a few tens of addresses. 39. # Nice separation between clients. 40. # The name you provide gets run through inet_aton(3), so you have to use dotted 41. # quad notation. This configuration is too important to trust some DNS. 42. 43. #Listen 192.68.0.5 44. 45. # User: The name or UID the server should run as. 46. # Group: The group name or GID the server should run as. 47. 48. User nobody 49. Group nobody 50. 51. # ServerAdmin: The email address where server problems should be sent. 52. # Note: this is not currently used, except as an environment variable 53. # for CGIs. 54. 55. #ServerAdmin root@localhost 56. 57. # ErrorLog: The location of the error log file. If this does not start 58. # with /, it is considered relative to the server root. 59. # Set to /dev/null if you don't want errors logged. 60. # If unset, defaults to /dev/stderr 61. 62. ErrorLog /var/log/boa/error_log 63. # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 64. # is somewhat experimental and might fail under heavy load. 65. # "Usual libc implementations of printf will stall the whole 66. # process if the receiving end of a pipe stops reading." 67. #ErrorLog "|/usr/sbin/cronolog --symlink=/var/log/boa/error_log /var/log/boa/error-%Y%m%d.log" 68. 69. # AccessLog: The location of the access log file. If this does not 70. # start with /, it is considered relative to the server root. 71. # Comment out or set to /dev/null (less effective) to disable 72. # Access logging. 73. 74. AccessLog /var/log/boa/access_log 75. # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 76. # is somewhat experimental and might fail under heavy load. 77. # "Usual libc implementations of printf will stall the whole 78. # process if the receiving end of a pipe stops reading." 79. #AccessLog "|/usr/sbin/cronolog --symlink=/var/log/boa/access_log /var/log/boa/access-%Y%m%d.log" 80. 81. # VerboseCGILogs: this is just a logical switch. 82. # It simply notes the start and stop times of cgis in the error log 83. # Comment out to disable. 84. 85. #VerboseCGILogs 86. 87. # ServerName: the name of this server that should be sent back to 88. # clients if different than that returned by gethostname + gethostbyname 89. 90. #ServerName www.your.org.here 91. 92. # VirtualHost: a logical switch. 93. # Comment out to disable. 94. # Given DocumentRoot /var/www, requests on interface 'A' or IP 'IP-A' 95. # become /var/www/IP-A. 96. # Example: http://localhost/ becomes /var/www/127.0.0.1 97. # 98. # Not used until version 0.93.17.2. This "feature" also breaks commonlog 99. # output rules, it prepends the interface number to each access_log line. 100. # You are expected to fix that problem with a postprocessing script. 101. 102. #VirtualHost 103. 104. # DocumentRoot: The root directory of the HTML documents. 105. # Comment out to disable server non user files. 106. 107. DocumentRoot /home/httpd/html 108. 109. # UserDir: The name of the directory which is appended onto a user's home 110. # directory if a ~user request is recieved. 111. 112. UserDir public_html 113. 114. # DirectoryIndex: Name of the file to use as a pre-written HTML 115. # directory index. Please MAKE AND USE THESE FILES. On the 116. # fly creation of directory indexes can be _slow_. 117. # Comment out to always use DirectoryMaker 118. 119. DirectoryIndex index.html 120. 121. # DirectoryMaker: Name of program used to create a directory listing. 122. # Comment out to disable directory listings. If both this and 123. # DirectoryIndex are commented out, accessing a directory will give 124. # an error (though accessing files in the directory are still ok). 125. 126. DirectoryMaker /usr/lib/boa/boa_indexer 127. 128. # DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker 129. # has been commented out, the the on-the-fly indexing of Boa can be used 130. # to generate indexes of directories. Be warned that the output is 131. # extremely minimal and can cause delays when slow disks are used. 132. # Note: The DirectoryCache must be writable by the same user/group that 133. # Boa runs as. 134. 135. # DirectoryCache /var/spool/boa/dircache 136. 137. # KeepAliveMax: Number of KeepAlive requests to allow per connection 138. # Comment out, or set to 0 to disable keepalive processing 139. 140. KeepAliveMax 1000 141. 142. # KeepAliveTimeout: seconds to wait before keepalive connection times out 143. 144. KeepAliveTimeout 10 145. 146. # MimeTypes: This is the file that is used to generate mime type pairs 147. # and Content-Type fields for boa. 148. # Set to /dev/null if you do not want to load a mime types file. 149. # Do *not* comment out (better use AddType!) 150. 151. MimeTypes /etc/mime.types 152. 153. # DefaultType: MIME type used if the file extension is unknown, or there 154. # is no file extension. 155. 156. DefaultType text/plain 157. 158. # AddType: adds types without editing mime.types 159. # Example: AddType type extension [extension ...] 160. 161. # Uncomment the next line if you want .cgi files to execute from anywhere 162. #AddType application/x-httpd-cgi cgi 163. 164. # Redirect, Alias, and ScriptAlias all have the same semantics -- they 165. # match the beginning of a request and take appropriate action. Use 166. # Redirect for other servers, Alias for the same server, and ScriptAlias 167. # to enable directories for script execution. 168. 169. # Redirect allows you to tell clients about documents which used to exist in 170. # your server's namespace, but do not anymore. This allows you to tell the 171. # clients where to look for the relocated document. 172. # Example: Redirect /bar http://elsewhere/feh/bar 173. 174. # Aliases: Aliases one path to another. 175. # Example: Alias /path1/bar /path2/foo 176. 177. Alias /doc /usr/doc 178. 179. # ScriptAlias: Maps a virtual path to a directory for serving scripts 180. # Example: ScriptAlias /htbin/ /www/htbin/ 181. 182. ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/ 183.
===================================================================
===================hosttest=======================================
1.进入boa-0.94.13/src
./configure
make
2.在etc/下建立boa目录并将boa.conf拷贝到该目录下.更改boa.conf
Group nogroup ===》Group 0
3.在 /var/log/下建立boa目录,该目录下可以查看boa服务器的日志
4.其它的一些路径
默认是/var/www下的内容可以访问 (DocumentRoot/var/www)
默认cgi :ScriptAlias/cgi-bin/ /usr/lib/cgi-bin/ (cgi可执行程序放在 /usr/lib/cgi-bin/目录下)
例子http://201.201.201.249/cgi-bin/cgi-test.cgi
CGIPath /bin:/usr/bin:/usr/local/bin
只有这些目录下的命令可以被调用,如果要root的权限(如ifconfig配置ip)需要加上/sbin
=====================================================================
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个字符是UserName=
// 在"UserName="和"&"之间的是我们要取出来的用户名
for ( i = 9; i < (int)strlen(input); i++ )
{
if ( input[i] == '&' )
{
name[j] = '\0';
break;
}
name[j++] = input[i];
}
// 前面9个字符 + "&Password="10个字符 + Username的字符数
// 是我们不要的,故省略掉,不拷贝
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>用户登陆验证</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><inputtype="password" name="Password"></td>
</tr>
<tr>
<td><inputtype="submit" value="登 录"></td>
<td><input type="reset"value="取 消"></td>
</tr>
</table>
</form>
</body>
</html>