【后台】嵌入式服务器Boa和CGI

大三的时候做过一个大学生创新项目,基于ZigBee的无线火警系统,后台使用的服务器就是自己在S3C2410开发板上移植搭建的Boa嵌入式web服务器。最近在复习做过的项目,顺便回顾了一下相关的内容。

一般的嵌入式web服务器有boa、lighttpd、thttpd等。与Apache等高性能的web服务器的主要区别是,Boa是一个单进程服务器,非常小巧,可执行代码只有约60KB,只能依次完成用户的请求,无法并发响应,但对于存储空间和运行内存空间有限的嵌入式设备已经足够了。而且Boa支持CGI,能为CGI程序fork出新的进程来处理。

Boa的设计目标是速度与安全。

Boa的移植:

1、环境:Ubuntu、S3C2410开发板、gcc交叉编译工具

2、步骤:

(1)下载Boa源码

(2)安装需要工具bison和flex

(3)修改文件

(4)生成Makefile文件(修改)

(5)编译

(6)Boa配置

(7)测试

具体过程:转载自博客http://blog.csdn.net/manchestermi/article/details/50826129

1.下载Boa源码

下载地址: http://www.boa.org/

最新发行版本: 0.94.13

下载 boa-0.94.13.tar.gz

解压:# tar xzf boa-0.94.13.tar.gz

2.安装需要工具bison,flex

sudo apt-get install bison flex

否则会出现如下错误

make: yacc:命令未找到
       make: *** [y.tab.c] 错误 127

make: lex:命令未找到
       make: *** [lex.yy.c] 错误 127

3.修改文件

(1)修改 src/compat.h

找到

#define TIMEZONE_OFFSET(foo) foo##->tm_gmtoff

修改成

#define TIMEZONE_OFFSET(foo) (foo)->tm_gmtoff

否则会出现错误:

util.c:100:1: error: pasting "t" and "->" does not give a valid preprocessing token make: *** [util.o] 错误 1

(2)修改 src/log.c

注释掉

if (dup2(error_log, STDERR_FILENO) == -1) {
                         DIE("unable to dup2 the error log");
                   }

为:

/*if (dup2(error_log, STDERR_FILENO) == -1) {
                         DIE("unable to dup2 the error log");
                   }*/

否则会出现错误:

log.c:73 unable to dup2 the error log:bad file descriptor

(3)修改src/boa.c

注释掉下面两句话:

if (passwdbuf == NULL) {
        DIE(”getpwuid”);
        }
        if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
        DIE(”initgroups”);
        }

#if 0
        if (passwdbuf == NULL) {
        DIE(”getpwuid”);
        }
        if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
        DIE(”initgroups”);
        }
        #endif

否则会出现错误:boa.c:211 - getpwuid: No such file or directory

注释掉下面语句:

if (setuid(0) != -1) {
                        DIE(”icky Linux kernel bug!”);
        }

#if 0
         if (setuid(0) != -1) {
                        DIE(”icky Linux kernel bug!”);
                }

#endif

否则会出现问题:boa.c:228 - icky Linux kernel bug!: No such file or directory

4、生成Makefile文件

执行:

#cd boa-0.94.13/src
         #./configure

5、修改Makefile

cd src
         vim Makefile

修改CC = gcc 为 CC = arm-linux-gcc

修改CPP = gcc -E 为 CC = arm-linux-gcc -E

6、编译

make

       ls -l boa
         -rwxr-xr-x 1 david david 189223 2009-05-31 13:44 boa

然后为生成的二进制文件boa瘦身

arm-linux-strip boa
      ls -l boa
         -rwxr-xr-x 1 david david 61052 2009-05-31 13:51 boa

可以发现boa的大小前后差距很大这为我们节省了很大的空间

7、Boa的配置

这一步的工作也在电脑主机上完成。

在boa-0.94.13目录下已有一个示例boa.conf,可以在其基础上进行修改。如下:

#vi boa.conf

(1)Group的修改

修改 Group nogroup

为 Group 0

(2)user的修改

修改 User nobody

为 User 0

(3)ScriptAlias的修改

修改ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

为 ScriptAlias /cgi-bin/ /var/www/cgi-bin/

(5)DoucmentRoot的修改

DoucmentRoot /var/www

(6)ServerName的设置

修改#ServerName www.your.org.here

为 ServerName www.your.org.here

否则会出现错误“gethostbyname::No such file or directory”

(7)AccessLog修改

修改AccessLog /var/log/boa/access_log

为#AccessLog /var/log/boa/access_log

否则会出现错误提示:“unable to dup2 the error log: Bad file descriptor”

(8)以下配置和boa.conf的配置有关,都是在ARM根文件系统中创建

以下步骤在开发板上进行:

创建目录/etc/boa并且把boa 和 boa.conf拷贝到这个目录下

mkdir /etc/boa

创建HTML文档的主目录/www

mkdir /var/www/cgi-bin

CGI脚本所在录 /var/www/cgi-bin

以下步骤在ubuntu下进行:

将boa.conf拷贝到开发板根文件系统的/etc/boa下

#cp boa.conf /source/rootfs/etc/boa

将boa拷贝到开发板根文件系统的/bin下

#cp src/boa /source/rootfs/bin

将ubuntu下/etc/mime.types拷贝到开发板根文件系统的/etc下

#cp /etc/mime.types /source/rootfs/etc

将你的主页index.html拷贝到 /var/www 目录下

8、测试

1)  HTML 脚本测试

如果我们要访问一个自己制作的网页(hello.html),可以在浏览器中输入http://192.168.184.100/hello.html,这里的IP地址就是开发板的IP地址。


2)  CGI脚本测试

还需配置CGI


1、编写Helloworld.c程序

在开始编写你自己的CGI程序之前,一定要先走通他的例子程序,免得后来程序出错的时候还不知道是配置有问题,还是你的程序代码有问题。
我们用他自带cgictest.c来实现自己的第一个C语言CGI程序。
你可以新建一个工作目录,用于存放你的CGI程序源代码,把cgic.h, cgic.c, cgictest.c三个文件拷贝到这个目录,然后建立一个Makefile文件,其内容为:
   1. test.cgi:cgictest.c cgic.h cgic.c
   2. gcc -wall cgictest.c cgic.c -o test.cgi
需要提醒的是,第二行开头一定是一个tab键(且仅有一个),不能使用空格。
保存好Makefile的内容之后,执行make命令:
make
我们看到,当前目录下应该多了一个test.cgi文件。
在你的网站根目录下建立一个cgi-bin目录(当然名字可以任意取,但作为习惯,一般叫做cgi-bin),然后在Apache的配置文件里赋予其执行CGI代码的权限,权限修改完之后要重启Apache。完成之后,把刚才生成的test.cgi放到cgi-bin目录中。此时我们可以在浏览器中输入以下地址进行访问:
http://127.0.0.1/cgi-bin/test.cgi
如果正常的话,应该看到一个网页被展示出来。这样,第一个C语言的CGI程序就运行起来了。
如果浏览器报错,那么多半是配置boa的时候有些操作没有正确完成。
3) 使用CGIC的基本思路
从cgic.c的代码可以看出,它定义了main函数,而在cgictest.c中定义了一个cgiMain函数。也就是说,对于使用CGIC编写的CGI程序,都是从cgic.c中的代码进入,在库函数完成了一系列必要的操作(比如解析参数、获取系统环境变量)之后,它才会调用你的代码(从你定义的cgiMain进入)。
另外一点就是,cgi程序输出HTML页面的方式都是使用printf把页面一行一行地打印出来,比如cgictest.c中的这一段代码:
fprintf(cgiOut, "<textarea NAME=\"address\" ROWS=4 COLS=40>\n");
fprintf(cgiOut, "Default contents go here. \n");
fprintf(cgiOut, "</textarea>\n");
上面这段代码的运行结果就是在页面上输出一个textarea。 第一个参数cgiOut实际上就是stdin,所以我们可以直接使用printf,而不必使用fprintf。不过在调试的时候会用到fprintf来重定向输出。
这种方式与Java Servlet非常类似,Servlet也是通过调用打印语句System.out.println(…)来输出一个页面。(不过后来Java推出了JSP来克服这种不便。)
但是与Servlet不同的地方在于,使用C语言的我们还要自己输出HTML头部(声明文档类型):
cgiHeaderContentType("text/html");
这个语句的调用一定要在所有printf语句之前。而这个语句执行的任务实际上就是:
void cgiHeaderContentType(char *mimeType) {
    fprintf(cgiOut, "Content-type: %s\r\n\r\n", mimeType);
}
这个语句告诉浏览器,这次传来的数据是什么类型,是一个HTML文档,还是一个bin文件… 如果是个HTML文档,就通过浏览器窗口显示,如果是一个bin(二进制)文件,则打开下载窗口,让用户选择是否保存文件以及保存文件的路径。
理解了这几点之后,你就可以编写自己的CGIC程序了。新建一个文件test.c试试:
下载: test.c
   1. #include <stdio.h>
   2. #include "cgic.h"
   3. #include <string.h>
   4. #include <stdlib.h>
   5. int cgiMain() {
   6.     cgiHeaderContentType("text/html");
   7.     fprintf(cgiOut, "<HTML><HEAD>\n");
   8.     fprintf(cgiOut, "<TITLE>My First CGI</TITLE></HEAD>\n");
   9.     fprintf(cgiOut, "<BODY><H1>Hello CGIC</H1></BODY>\n");
  10.     fprintf(cgiOut, "</HTML>\n");
  11.     return 0;
  12. }
把Makefile文件中的cgitest.c全部换称test.c,保存,再执行make命令即可。
此时通过浏览器访问,会在页面上看到一个大大的“Hello CGIC”。

2、浏览

    将helloworld.cgi拷贝至/var/www/cgi-bin/下,浏览器输入

    http://192.168.0.126/cgi-bin/test.cgi


打开一个浏览器输入开发板ip看看效果

OK