扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
嵌入式 WEB 服务器 BOA 和 CGI
一、嵌入式 WEB 服务器 BOA 简介
嵌入式 WEB 服务器常见的有:
boa
lighttpd
shttpd
thttpd
mathopd
minihttpd
appweb
goahead
随着 Internet 技术的兴起,在嵌入式设备的管理与交互中,基于 Web 方式
的应用成为目前的主流,这种程序结构也就是大家非常熟悉的 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 是一个非常小巧的 Web 服务器,可执行代码只有约 60KB。它是一个单
任务 Web 服务器,只能依次完成用户的请求,而不会 fork 出新的进程来处理
并发连接请求。但 Boa 支持 CGI,能够为 CGI 程序 fork 出一个进程来执行。
Boa 的设计目标是速度和安全,在其站点公布的性能测试中,Boa 的性能 要好
于 Apache 服务器。
Boa 程序的移植见附录一。
二、CGI 和 CGIC 简介
1、CGI
目前 Web 技术中生成动态 Web 页面的方法有 CGI 和服务器脚本,如 JSP,
ASP 等,但后者需要 Web 服务器具有这些脚本的运行支持模块。在嵌入式 Web
服务器中,考虑到资源限制问题,一般都只提供 CGI 支持,因此在嵌入式设备
中 Web 方式应用实际上就是基于 CGI 的程序开发。
CGI(Common Gateway Intergace 通用网关界面)是一段运行在 Web 服务
器上的程序,提供同客户端 Html 页面的接口。我们举个实际例子:常见的个人
主页上大都有一个留言本,留言本的工作方式是这样的:先由用户输入一些信
息,如名字之类的东西,接着用户按一下“留言”(到目前为止工作都在客户
端),浏览器就把这些信息传送到服务器的 CGI 程序中,于是 CGI 程序在服务
器上按照预定的方法进行处理,在本例中就是把用户提交的信息存入指定的文
件中,最后 CGI 程序给客户端发回一个“留言结束”字样的页面,用户可以在
浏览器里看到。
在进行 CGI 编程之前,我们先了解 HTML 的一些知识。CGI 可以使用多种编程
语言来实现,包括 C、 C++、Perl 等,但在嵌入式设备的开发中,一般都不会
采用 Perl 等解释性语言,因为这种语言还需要有解释执行的支撑模块,会占用
存贮空间和内存,最常用的方法当然是用 C 来编写,但 C 并不是很适合开发象
CGI 这种需要大量进行字符串操作的程序,编程比较烦琐,因此,对于一个专
业的开发人员来说,首先想到的应该是有没有可复用的库来支持快速高效的开
发 CGI 程序。幸运的是目前就有不少开放源码的支持 CGI 开发的 C 库。我们在
此只介绍 CGIC,有兴趣的朋友可以自己在 Internet 上搜索其他的 C 库。
2、CGIC
CGIC 是一个支持 CGI 开发的开放源码的标准 C 库,可以免费使用,只需要
在开发的站点和程序文档中有个公开声明即可,表明程序使用了 CGIC 库,用户
也可以购买商业授权而无需公开声明。
CGIC 能够提供以下功能:
1 分析数据,并自动校正一些有缺陷的浏览器发来的数据;
2 透明接收用 GET 或 POST 方法发来的 From 数据;
3 能接受上传文件;
4 能够设置和接收 cookies;
5 用一致的方式处理 From 元素里的回车;
6 提供字符串,整数,浮点数,单选或多选功能来接收数据;
7 提供数字字段的边界检查;
8 能够将 CGI 环境变量转化成 C 中的非空字符串;
9 提供 CGI 程序的调试手段,能够回放 CGI 程序执行时的 CGI 状态;
总之,CGIC 是一个功能比较强大的支持 CGI 开发的标准 C 库,并支持 Linux,
Unix 和 Windows 等多操作系统。
使用 CGIC 的基本思路:
从 cgic.c 的代码可以看出,它定义了 main 函数,而在 cgictest.c 中
定义了一个 cgiMain 函数。也就是说,对于使用 CGIC 编写的 CGI 程序,都
是从 cgic.c 中的代码进入,在库函数完成了一系列必要的操作(比如解析参
数、获取系统环境变量)之后,它才会调用你的代码(从你定义的 cgiMain 进
入)。
CGIC 库的 移植与 cgi 编写测试见附录二。
附录一:Boa 程序的移植(未测试,仅供参考,先用现成的)
第一步完成 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-linuxgcc,再找到 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 目录下。
==================================================
=================
===================host
test=======================================
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
附录二:CGIC 库移植(测试通过,目标是路由器,mips架构)
一、CGIC 的移植过程:
从 CGIC 的主站点 http://www.boutell.com/cgic/下载源码,当前最
新版本是 2.05 版。在任一目录将其解压并进入源码目录。
# tar xzf cgic205.tar.gz
# cd cgic205
# chmod 777 cgic205
修改 cgic205 中 Makefile 文件,
1. 找到 CC=gcc,将其改成 CC= mipsel -linux-gcc,
2. 找到 AR=ar,将其改成 AR= mipsel -linux-ar,
3. 找到 RANLIB=ranlib,将其改成 RANLIB= mipsel -linux-ranlib。
4. 找到 gcc cgictest.o -o cgictest.cgi ${LIBS},将其改成$(CC)
$(CFLAGS) cgictest.o -o cgictest.cgi ${LIBS},
5. 找到 gcc capture.o -o capture ${LIBS},将其改成$(CC)
$(CFLAGS) capture.o -o capture ${LIBS},
6. 文件存放路径:找到
install: libcgic.a
cp libcgic.a /usr/local/lib
cp cgic.h /usr/local/include
改成:
install: libcgic.a
cp libcgic.a /work/RT288x_SDK/RT288x_SDK/source/lib/lib
cp cgic.h
/work/RT288x_SDK/RT288x_SDK/source/user/boa/cgi-bin
注意 cp 等命令前以 tab 键开头,不要用空格键。
接下来第 7,8 两步要获取反转意函数功能:
7.打开 cgic.c,找到这一行语句:
static cgiUnescapeResultType cgiUnescapeChars(char **sp,
char *cp, int len);
将 static 去掉,将声明添加到 cgic.h,加 extern:
extern cgiUnescapeResultType cgiUnescapeChars(char **sp,
char *cp, int len);
8. 将结构体:
typedef enum {
cgiUnescapeSuccess,
cgiUnescapeMemory
} cgiUnescapeResultType;
把这几行语句复制到 cgic.h 文件中,并在这里把它注释掉:
#if 0
typedef enum {
cgiUnescapeSuccess,
cgiUnescapeMemory
} cgiUnescapeResultType;
#endif
并保存退出。 然后运行 make 进行编译。
添加编译器路径:
#export PATH=$PATH:/opt/buildroot-gcc342/bin/
#make
#make install
这样 就生成库文件 libcgic.a。
接下来用 cgic 编写一个 cgi 例子:
二、用 cgic 编写一个 cgi
1. 写一段完整代码 cgi_string_escape.c,保存到文件夹
/work/RT288x_SDK/RT288x_SDK/source /user/boa/cgi-bin 。
#include
#include "cgic.h"
#include
#include
extern char *cgiQueryString;
extern cgiUnescapeResultType cgiUnescapeChars(char **sp,
char *cp, int len);
int cgiMain() {
char * buffer;
cgiHeaderContentType("text/html");
fprintf(cgiOut, "n");
fprintf(cgiOut, "
fprintf(cgiOut, "");
cgiUnescapeChars(&buffer, cgiQueryString,
strlen(cgiQueryString));
fprintf(cgiOut, "I LOVE CGIC!东明电子研发部
");
fprintf(cgiOut, "%s
",buffer);
fprintf(cgiOut, "n");
fprintf(cgiOut, "n");
return 0;
}
2. 修改/work/RT288x_SDK/RT288x_SDK/source /user/boa/cgibin 下 makefile 文件。在相似处添加文件信息。
1)在 LDLIBS += -lnvram 下添加链接库
LDLIBS += -lcgic
2)在 CGI_STRING = cgi_string.cgi 下添加变量
CGI_STRING_ESCAPE = cgi_string_escape.cgi
3)在 ALL_EXE += $(CGI_STRING)下添加
ALL_EXE += $(CGI_STRING_ESCAPE)
4)在
$(CGI_STRING): cgi_string.o
$(CC) -o $@ cgi_string.o $(LDFLAGS) $(EXTRALIBS)
$(LDLIBS)
下添加规则:
$(CGI_STRING_ESCAPE): cgi_string_escape.o
$(CC) -o $@ cgi_string_escape.o $(LDFLAGS) $(EXTRALIBS)
$(LDLIBS)
5)在
$(ROMFSINST) $(WEB_DIRECTORY)/cgi-bin/$(CGI_STRING)
下添加:
$(ROMFSINST) $(WEB_DIRECTORY)/cgibin/$(CGI_STRING_ESCAPE)
6)在
cgi_dtring.o: cgi_dtring.c $(CONF_H) $(UCONF_H)
$(BUSYBOXCONF_H) $(CGIC_H)
下添加依赖关系:
cgi_dtring_escape.o: cgi_dtring_escape.c $(CONF_H)
$(UCONF_H) $(BUSYBOXCONF_H) $(CGIC_H)
保存退出。
3.到路径下/work/RT288x_SDK/RT288x_SDK/source/编译工程。将
RT288x_SDKRT288x_SDKsourceimages 中 uImage 烧
写到机器。
4.局域网中:将 pc 机 ip 地址改成与机器同一网段.
Ip 地址:192.168.0.132
网关:192.168.0.1
5.在浏览器中输入:
http://192.168.0.178/cgi-bin/cgi_string_escape.cgi?东明电子
company!
注意字符前用?号连接。将字符“东明电子 company!”传给服务
器。
网页中接受反馈显示如下则测试通过: (本例结束。)
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流