Chinaunix首页 | 论坛 | 博客
  • 博客访问: 555319
  • 博文数量: 99
  • 博客积分: 5015
  • 博客等级: 大校
  • 技术积分: 1209
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-28 23:08
文章存档

2011年(7)

2010年(6)

2009年(86)

我的朋友

分类: LINUX

2009-06-19 09:15:05

注:最近在做goAhead web server和移植其到TI芯片+linux上,这里先转一篇相关的文章来学习下,希望有所帮助。。。
*******************************
* web server大全之GoAhead移植 *
*******************************
    2009/02/14  asdjf@163.com  
    
    很多人希望在产品中使用Web Server,为此,我们总结了十几种各式各样的Web Server任君选择。Web Server开发再也不是困难的事情了。
    
    本文档介绍强大的嵌入式Web服务器GoAhead!!!
    它的主要特点是:
    
    1、支持ASP。
    2、嵌入式JavaScript---Ejscript。
    3、支持标准的CGI。
    4、支持内存中的CGI处理。
    5、快速响应,每秒可处理超过65个请求。
    6、符合HTTP 1.0/HTTP 1.1标准。
    7、拥有众多扩展API,方便用户开发。
    8、支持SSL 3.0.
    9、支持用户群组管理。
    10、支持DAA访问认证。
    11、小内存,如果不包含SSL,仅要求60K的内存:包含SSL,要求500K内存。
    12、Web页面可以存在于ROM或文件系统中。
    13、支持多种操作系统,如:eCos、Linux、LynxOS、QNX、VxWorks、WinCE、pSOS等。
    

    
    图1 GoAhead运行效果。
 图2 GoAhead源程序结构框图
GoAhead Web服务器是GoAhead公司早期推出的一种可以运行于多种平台的小巧而精致的Web服务器,它具有移植性好、开放源代码、代码量小的特点。GoAhead Web服务器特别适合于嵌入式系统。
    
    GoAhead Web服务器的详细说明文档位于GoAhead源码中的webs/docs目录下,源码可以从下载。注意:由于目前eCos不支持用户群组,因此eCos不支持GoAhead的用户管理和访问控制功能。
    
    解压缩GoAhead源码到/g目录,可以看到GoAhead源码组织结构如下:
    /g
     |
     |\______各种OS移植子目录(如:ecos子目录)
     |\______Web自目录(用来保存自己设计的网页)
     |\______GoAhead服务器源码(C程序)
      \______webcomp.c网页编译器
    
    和通常的Web Server不同,我们设计的网页(ASP、html等)在编译阶段就被解析并和服务器源码编译到了一起,而不是象其他服务器那样在运行阶段读取网页并解析内容。
    
    GoAhead根目录下的webcomp.c网页编译器负责把Web子目录下的所有Web网页进行转换,使其能够与GoAhead Web服务器源码以及eCos其他应用代码一起编译。
    web子目录下是所有Web网页内容。Web服务器的所有网页都必须放置在该目录下。
    eCos子目录包含了与eCos的接口,包括main.c文件和makefile文件。用户根据实际需要可以对main.c和makefile文件进行修改。
    
    通过阅读ecos目录下的makefile文件可知,GoAhead Web服务器编译过程主要有三个步骤:
    1、编译webcomp.c文件,生成网页编译器webcomp.exe。webcomp.c使用本地编译器gcc进行编译,编译后的网页编译器位于ecos子目录下。网页编译器将web子目录下的所有网页进行转换并生成webcomp.c文件。webcomp.c文件将存放于ecos子目录下。
    2、交叉编译器对GoAhead根目录下的Web服务器源码和网页文件webcomp.c进行编译,生成库文件libwebs.a。
    3、eCos应用程序在编译时与库文件libwebs.a进行链接,生成可运行于目标平台的可执行文件。
    
    以下是ecos子目录下的makefile文件,从中可以看出这三个步骤的执行过程。
    
# eCos makefile

all: compile

#
# These definitions come from your eCos install tree
#
DEBUG := -g -Wall -O2

# For Cirrus Logic EDB72xx board
PKG_INSTALL_DIR := /tmp/untitled_install
COMMAND_PREFIX := arm-elf-
CFLAGS := -mcpu=arm7tdmi $(DEBUG)

# For Motorola PowerPC MBX/860
##PKG_INSTALL_DIR := /work/net_mbx/install
##COMMAND_PREFIX := powerpc-eabi-
##CFLAGS := -mcpu=860 -msoft-float $(DEBUG)

#
# These should not need to be changed
#
CC := $(COMMAND_PREFIX)gcc
OBJCOPY := $(COMMAND_PREFIX)objcopy
AR := $(COMMAND_PREFIX)ar
LDFLAGS = -nostartfiles -L$(PKG_INSTALL_DIR)/lib -Wl,--gc-sections $(LIBS)
LIBS = -Ttarget.ld -nostdlib
CXXFLAGS      = $(CFLAGS)
EXTRACFLAGS   = -Wall -I$(PKG_INSTALL_DIR)/include -ffunction-sections -fdata-sections
EXTRACXXFLAGS = $(EXTRACFLAGS) -fno-exceptions -fno-rtti -fvtable-gc -finit-priority

# eCos build rules
%.o: %.c
$(CC) -c -o $*.o $(CFLAGS) $(EXTRACFLAGS) -Wp,-MD,$*.d $<

%.d: %.c
$(CC) -E $(CFLAGS) $(EXTRACFLAGS) -Wp,-MD,$*.d $< >/dev/null

%.o: %.cxx
$(CXX) -c -o $*.o $(CXXFLAGS) $(EXTRACXXFLAGS) $<

%.o: %.C
$(CXX) -c -o $*.o $(CXXFLAGS) $(EXTRACXXFLAGS) $<

%.o: %.cc
$(CXX) -c -o $*.o $(CXXFLAGS) $(EXTRACXXFLAGS) $<


#------------------- GoAheadWebServer stuff --------------------
ARCH = libwebs.a
NAME = webs
OBJ_FILES = ../asp.o ../balloc.o ../base64.o ../default.o  \
  ../ejlex.o ../ejparse.o ../form.o \
  ../h.o ../handler.o ../mime.o ../misc.o ../page.o  \
  ../ringq.o ../rom.o \
  ../sock.o ../sockGen.o \
  ../security.o ../sym.o ../uemf.o ../url.o ../value.o \
  webrom.o ../webs.o ../websuemf.o
DEPEND_FILES = $(patsubst %.o,%.d,$(OBJ_FILES) main.o)
CFLAGS += -DWEBS -DUEMF -DWEBS_PAGE_ROM -DOS="eCos" -DECOS -D__ECOS -D__NO_FCNTL=1 -I..

.PHONY: depend clean

compile: $(NAME)

depend: $(DEPEND_FILES)
find .. -name "*.d" | xargs cat >.depend

#
# Build archive of objects
#
$(ARCH): $(OBJ_FILES)
$(AR) $(ARFLAGS) $(ARCH) $?

#
# Primary link
#
$(NAME): Makefile  main.o $(ARCH)
$(CC) -o $(NAME) $(CFLAGS) $(IFLAGS) \
main.o $(ARCH) $(LDFLAGS)

clean:
rm -f $(NAME) $(ARCH) $(DEPEND_FILES) $(OBJ_FILES)
rm -f main.o webrom.c webcomp web_files .depend

#
# This tool needs to be built using the native C compiler
#
webcomp:
gcc -o webcomp -O2 -DWEBS -DUEMF -DOS="Linux" -DLINUX -D_STRUCT_TIMEVAL -I.. ../webcomp.c

#
# Build a set of ROMable pages
#
webrom.c: webcomp
find ../web -name "*.*" >web_files
./webcomp ../web web_files >webrom.c

# Dependencies

-include .depend

    我们修改了makefile中的几个定义:
    1、PKG_INSTALL_DIR := /tmp/untitled_install 指向《ecos增值包》提供的系统库文件。
    2、修改cc为gcc,cygwin环境下编译器为gcc。增加-D_STRUCT_TIMEVAL定义,以避免uemf.h中的struct timeval结构体定义和ecos库中的已有定义冲突。
        gcc -o webcomp -O2 -DWEBS -DUEMF -DOS="Linux" -DLINUX -D_STRUCT_TIMEVAL -I.. ../webcomp.c

    除了makefile需要修改外,main.c文件需要将最后的send()和recv()函数定义注释掉,因为和ecos库里已有的定义冲突。

/******************************************************************************/
/*
* Wrappers for depreciated socket I/O functions
*/
/*
int send(int s, const void *buf, size_t len, int flags)
{
    return write(s, buf, len);
}

int recv(int s, void *buf, size_t len, int flags)
{
    return read(s, buf, len);
}
*/
/******************************************************************************/

    根目录下sockGen.c文件中需要增加如下定义,以避免编译错误。
    #include "sys/select.h"
    #define NFDBITS __NFDBITS
    
    根目录下uemf.h中的下列定义冲突,注释掉即可。
    //#define O_RDONLY 1

    根目录下wsIntrn.h中增加下列引用,以避免编译错误。
#ifdef ECOS
#include
#include
#endif

    上面讲的都是GoAhead本身的修改,对于我们应用来说,还需要修改ecos目录下的main.c文件。移植时通常需要修改两个地方:ecos的入口点函数main()和Web服务器的初始化函数initWebs()。
    
    1、Web服务器的启动。main.c文件主要用于对Web服务器进行独立的测试和调试,因此可以直接使用main()函数来启动Web服务器,但是在实际项目开发中,GoAhead Web服务器通常只是eCos应用软件的一个功能模块,这种情况下,可以将Web服务器当成一个线程来启动。
    
    下面的代码就是把Web服务器当成线程启动的一个实例。线程入口函数goahead_program()就是原来main.c文件中的main()入口函数。代码中的Web服务器的线程优先级为16,线程名为"GoAhead Web Server"。eCos应用程序通过调用do_webs()函数来启动Web服务器线程。这种情况下,最好是修改main.c文件名并将其加入到eCos应用程序项目中,与其他源码程序一起编译。此时使用的makefile文件可参考《第十二讲 多目录下makefile的通用写法》文档。

#include  "../uemf.h"
#include  "../wsIntrn.h"
#include  

cyg_handle_t webs_thread_handle;
cyg_thread webs_thread_s; //space for web thread objects
char webs_stack[4096];    //space for 4K stacks
cyg_thread_entry_t goahead_program;

void do_webs(int argc, char *argv[])
{
    cyg_thread_create(16, goahead_program, (cyg_addrword_t) 0,
                      "GoAhead Web Server", (void *)webs_stack, 163840,
                      &webs_thread_handle, &webs_thread_s);
    cyg_thread_resume(webs_thread_handle);
}

void goahead_program(cyg_addrword_t data)
{
    bopen(NULL, (60 * 1024), B_USE_MALLOC);
   
    if (initWebs() < 0) {
        return -1;
    }
    
    while (!finished) {
        if (socketReady(-1) || socketSelect(-1, 2000)) {
            socketProcess(-1);
        }
        emfSchedProcess();
    }
    
    websCloseServer();
    socketClose();
    bclose();
    return 0;
}
    
    2、Web初始化函数。Web服务器入口程序有一个initWeb()函数,用于对GoAhead Web服务器的初始化操作。
    
    初始化函数initWeb()首先调用init_network_interfaces()对网络进行初始化。如果在Web服务器启动之前已经对网络进行了初始化操作,那么initWeb()函数则可以省去这一步。随后,initWeb()对Web服务器进行配置操作,包括访问口令、服务器端口号、默认访问页面等。有几个可能需要修改的配置语句:
    
    设置根目录:
        websSetDefaultDir("/");
    
    设置默认访问页default.asp:
        websSetDefaultPage(T("default.asp"));
    
    设置访问口令(不需要口令时为空):
        websSetPassword(password);
    
    Web服务器端口和重试次数:
        websOpenServer(port, retries);
    
    initWeb()函数中另一处需要修改的地方是定义自己的表单处理程序和ASP script处理函数。GoAhead采用内存CGI处理的方法,而不需另外启动单独的CGI程序。对于用C语言写的所有表单处理CGI函数和ASP script处理函数,在intiWeb()函数中分别调用下面两个函数对它们进行定义:
    
    int websFormDefine(char_t *name, void (*fn)(webs_t wp, char_t *path, char_t *query));
    int websAspDefine(char_t *name, int (*fn)(int ejid, webs_t wp, int argc, char_t **argv));
    
    在main.c文件中有两个例子可以参考,一个是用于表单(forms.asp)处理的CGI程序formTest,另一个是内嵌在ASP页面(asp.asp)中的javascript处理程序aspTest。这两个函数在initWeb()函数内的定义如下:
    
    websAspDefine(T("aspTest"), aspTest);
    websFormDefine(T("formTest"), formTest);
    
    以ASP的处理函数为例,这里的webAspDefine(T("aspTest"), aspTest)函数将aspTest()定义为ASP script处理函数,用户可提供相关的函数aspTest来进行想要完成的功能,例如:
    
static int aspTest(int eid, webs_t wp, int argc, char_t **argv)
{
    char_t *name, *address;

    if (ejArgs(argc, argv, T("%s %s"), &name, &address) < 2) {
        websError(wp, 400, T("Insufficient args\n"));
        return -1;
    }

    return websWrite(wp, T("Name: %s, Address %s"), name, address);
}
    
    然后在ASP页面asp.asp中调用该Asp script函数即可,如调用上述例子:
    
    

Expanded ASP data: <% aspTest("Peter Smith", "112 Merry Way"); %>


    
    在对eCos子目录下的makefile文件、main.c文件、web子目录的网页内容及根目录下的若干文件进行修改后,在Cygwin环境下首先进入到Web服务器源码的eCos子目录,然后直接使用make命令就可以完成GoAhead的编译过程。使用make clean可以清除编译垃圾,当修改了Web服务器源码、网页内容和main.c文件后,都必须使用该命令清除前一次的编译结果和编译中间文件,否则,程序运行可能不正常。
    
    如果只是修改了main.c文件,那么可以直接使用下面命令进行eCos应用程序编译:
    
    $arm-elf-gcc main.c -o webs -g -DWEBS -DUEMF -DWEBVS_PAGE_ROM
                 -DOS="eCos" -DECOS -D__ECOS -D__NO_FCNTL=1
                 -I.. -I/h/ecos-work/mywork_install/include
                 -L/h/ecos-work/mywork_install/lib libwebs.a
                 -Ttarget.ld -nostdlib -Wall -Wl,--gc-sections
    
    该应用程序直接使用了前面已经编译好的库文件libwebs.a。当eCos应用程序包含多个源码文件时,可参考《第十二讲 多目录下makefile的通用写法》文档。命令中第三行的两个“-I”分别指定了GoAhead和eCos的头文件路径,第四行指定了eCos的库文件路径和GoAhead Web服务器库文件libwebs.a。实际使用时要根据具体路径进行修改。
图3 JavaScript测试
 
图4 ASP表单Form测试输入
 
 图5 ASP表单Form测试输出结果
 
网页设计举例
    
    前面已经对ASP网页的内嵌函数进行了说明。这里我们讨论ASP网页的设计方法。下面是GoAhead Web服务器源码中的一个表单网页forms.asp:

GoForm Test












    
      

Name:
Address:

        




forms.asp是一个提交姓名和地址的页面,它调用CGI程序formTest对表单进行处理。formTest是一个内存CGI程序,它必须在initWebs()函数中使用websFormdefine()进行定义。main.c中提供了一个表单处理函数的例子:

static void formTest(webs_t wp, char_t *path, char_t *query)
{
    char_t *name, *address;

    name = websGetVar(wp, T("name"), T("Joe Smith"));
    address = websGetVar(wp, T("address"), T("1212 Milky Way Ave."));

    websHeader(wp);
    websWrite(wp, T("

Name: %s, Address: %s

\n"), name, address);
    websFooter(wp);
    websDone(wp, 200);
}

    该表单处理CGI程序首先获取name和address两个变量值,然后再将表单输入的内容以单独的一个页面进行输出。从formTest函数的最后四行还可以看出页面输出的四个基本函数。图4和图5为表单输入和输出的两个页面。
阅读(9546) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

chinaunix网友2009-12-29 18:44:36

很好,赞一个~