《Web服务移植thttpd在ARM移植精品资料.doc》由会员分享,可在线阅读,更多相关《Web服务移植thttpd在ARM移植精品资料.doc(23页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、thttpd在ARM移植1 下载并解压:下载地址为: 下载的是最新的2.25b解压: rootBinnary source# tar -xvzf thttpd-2.25b.tar.gz2 交叉编译thttpd rootBinnary source # cd thttpd-2.25brootBinnary thttpd-2.25b # CC=/armtools/bin/arm-linux-gcc ./configure -host=arm-linuxrootBinnary thttpd-2.25b # make3 安装与配置3.1 拷贝thttpd二进制可执行文件到根文件系统/usr/sbin/
2、目录中 rootBinnary thttpd-2.25b # cp thttpd /fs/usr/sbin/3.2 拷贝thttpd配置文件rootBinnary thttpd-2.25b # cp contrib/redhat-rpm/thttpd.conf /fs/etc/3.3在开发板上为thttpd创建一个独立的用户:httpd,并用此用户创建httpd服务的根目录html root/root#adduser httpd(在ARM开发板上去添加用户)Changing password for httpdEnter the new password (minimum of 5, maxi
3、mum of 8 characters)Please use a combination of upper and lower case letters and numbers.Enter new password:Bad password: too short.Warning: weak password (continuing).Re-enter new password:passwd786: password for httpd changed by user rootPassword changed.root/root#exitprocess -/bin/login (pid 787)
4、 exited. Scheduling it for restart.starting pid 790, tty : /bin/login192.168.1.2 login: httpdPassword:Processing /etc/profile.Set search library path in /etc/profileSet user path in /etc/profileSet PS1 in /etc/profileDonehttpd/home/httpd #mkdir html 3.4 拷贝测试网页到httpd服务的根目(可选,测试之用): rootBinnary thttpd
5、-2.25b # cp index.html /fs/home/httpd/html/我是动态编译所以查看一下需要的动态库 rootBinnary thttpd-2.25b # /armtools/bin/arm-linux-readelf -d thttpdDynamic section at offset 0x12014 contains 21 entries:Tag Type Name/Value0x00000001 (NEEDED) Shared library: libcrypt.so.10x00000001 (NEEDED) Shared library: libc.so.60x0
6、000000c (INIT) 0x95480x0000000d (FINI) 0x165640x00000004 (HASH) 0x81280x00000005 (STRTAB) 0x8c140x00000006 (SYMTAB) 0x84940x0000000a (STRSZ) 1066 (bytes)0x0000000b (SYMENT) 16 (bytes)0x00000015 (DEBUG) 0x00x00000003 (PLTGOT) 0x220e40x00000002 (PLTRELSZ) 872 (bytes)0x00000014 (PLTREL) REL0x00000017 (
7、JMPREL) 0x91e00x00000011 (REL) 0x91a00x00000012 (RELSZ) 64 (bytes)0x00000013 (RELENT) 8 (bytes)0x6ffffffe (VERNEED) 0x91300x6fffffff (VERNEEDNUM) 20x6ffffff0 (VERSYM) 0x903e0x00000000 (NULL) 0x0虽然这里只列出了需要libcrypt 和 libc 这两个动态库,但是想要运行thttpd还需要libnss_files 动态库,具体原因如下解释: rootBinnary thttpd-2.25b$ cp -d
8、 /armtools/arm-linux/lib/libnss_files* /fs/lib/你可以在启动文件里增加thttpd的启动命令:thttpd -C /etc/thttpd.conf注意只有root有启动权限!4、增加对CGI的支持默认配置下,thttpd不可以运行GCI(特别是动态编译的CGI程序)要想使用CGI支持功能,必须更改thttpd.conf的配置:# This section overrides defaultsdir=/home/httpd/html#chroot#屏蔽chroot是为了运行动态编译的CGIuser=httpd# default = nobodylog
9、file=/var/log/thttpd.logpidfile=/var/run/thttpd.pid# This section _documents_ defaults in effectport=80port参数用于更改端口号(可不改,若还运行了别的WEB服务器,则需用不同端口)# nosymlink# default = !chroot#symlinks# novhostcgipat=/cgi-bin/*声明CGI程序的目录,是以dir为根目录的路径# nothrottles# host=0.0.0.0# charset=iso-8859-1移植完成,可以测试了(只需在WEB浏览器中键
10、入开发板的IP地址即可)。在建立 embedded Linux 系统 (root filesystem) 时,链接库相依 (library dependencies)是相当重要的目。当 root filesystem 缺少必要的 library 时,程序当然是无法执行的,甚致系统也会无法顺利启动。在建构 embedded Linux 系统时,应具备的正确观念与基本能力。我们把如何找出所需的 library方法整理出 3 项的基本要点,依照这 3 种基本款来加入 library 将能解决几乎所有的 library dependency 问题,这 3 种项基本要点为:(1) 先利用 cross t
11、oolchain 的 objdump 观察NEEDED的项目,加入 library。(2) 再检查这些 library 是否相依其它 library。(3) 最后要检视应用程序是否使用到需要特定 library 的service。要点 1. 跟 2. 对大家来说没有什么问题,要点 3. 在我们的 training 课程里,我们以建构 thttpd (embedded Web server) 的实际案例来做讲解。关于建构 thttpd 的案例thttpd 使用到 NSS (Name Service Switch),因此若没有将 libnss_SERVICE.so 加到 root filesyst
12、em,thttpd 在执行时可能会遇到一些奇怪的问题。举个例子,当 thttpd 透过 /etc/passwd 去寻找 (查询) UNIX user 时,会用到 libnss_files.so (不读 /etc/shadow),因此会看到以下的错误讯息:unknown user - root出现这个错误的原因是 thttpd 读不到 root 使用者,要深入探讨这个问题的原理,必须从以下的程序代码片断开始探讨: 403 /* If were root and were going to become another user, get the uid /gid 404 * now. 405 *
13、/ 406 if ( getuid() = 0 ) 407 408 pwd = getpwnam( user ); 409 if ( pwd = (struct passwd*) 0 ) 410 411 syslog( LOG_CRIT, unknown user - %.80s, user ); 412 (void) fprintf( stderr, %s: unknown user - %sn, argv0, user ); 413 exit( 1 ); 414 415 uid = pwd-pw_uid; 416 gid = pwd-pw_gid; 417 这段程序代码是 thttpd 2
14、.25b 的程序片断,位于 thttpd.c 的 main() 函数里。关于 libnss_SERVICE.so 的议题,Jollen 打算另外再做讨论,因为还会与 libc 有关系。在这里我们由系统建构的角度来看这个问题。因为我们已经习惯用 objdump 来观察程序的相依 library,所以当 objdump 的画面跟我们预期的不同时,经常一时无法反应过来。例如,以下的讯息是我们所预期的:# /armtools/bin/arm-linux-objdump -x thttpd|more.Dynamic Section: NEEDED libcrypt.so.1 NEEDED libnss_
15、files.so.2 NEEDED libc.so.6.但是实际的讯息却是像这样的:#/armtools/bin/arm-linux-objdump -x thttpd|more.Dynamic Section: NEEDED libcrypt.so.1 NEEDED libc.so.6.我们可以用一知半解的思考逻辑来解决问题:thttpd 呼叫到 getpwnam() 函数,此函数由 libnss_compat 提供,因此解决方案是把 libnss_files.so 加到 root filesystem 里即可。且慢!前面才讲到 libnss_compat,怎么后面是把 libnss_fil
16、es 加到 root filesystem?是这样的,libnss_compat 用来读 /etc/shadow,但是现在我们只需要由 /etc/passwd 读 Unix user,所以使用 libnss_files.so 就行了。执行 thttpd 的话,再加上指定 username 的参数来执行:# thttpd -p 80 -d /var/www -u rootlibnss_SERVICE.so 是包含在 glibc 里的链接库,因此可以直接由 cross toolchain 里取得,不必再另行建置。有关 NSS (Name Service Switch) 可参考以下网页:http:/
17、www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.htmlhttp:/mirrors.usc.edu/pub/gnu/Manuals/glibc-2.2.3/html_chapter/libc_28.html此处我们以service的角度来探讨这个问题:因为 thttpd 使用到 Name Service Switch,所以需要加入 libnss_SERVICE.so。另外一种探讨的角度是:由 programming 的角度来思考。如果要读 shadow passwd 的话,是使用 libnss_compat.so。B
18、oa程序的移植1、下载Boa源码 下载地址: http:/www.boa.org/ 目前最新发行版本: 0.94.13 (几年没更新版本了) 下载 boa-0.94.13.tar.gz,注意:若从boa上下载的是boa-0.94.13.tar.tar,解压方式一样 解压: rootBinnary source# tar xzf boa-0.94.13.tar.gz2、生成Makefile文件进入boa-0.94.13,直接运行src/configure文件 rootBinnary src#CC=/armtools/bin/arm-linux-gcc ./configure#3、修改Makefi
19、le文件(注意:必须用cross-2.95.3, 如使用3.4.1、4.1.1等等会出错) #CC = /armtools/bin/arm-linux-gcc #CPP = /armtools/bin/arm-linux-gcc -E4、交叉编译 rootBinnary src# make5、去除调试信息,减小体积。(可选) rootBinnary src# /armtools/bin/arm-linux-strip boa6、将编译好的程序放入根文件系统的/bin目录下。 rootBinnary src# cp boa /fs/bin/ 二、配置BoaBoa需要在/etc目录下建立一个boa
20、目录,里面放入Boa的主要配置文件boa.conf。在Boa源码目录下已有一个示例boa.conf,可以在其基础上进行修改。 rootBinnary src# cd ./.rootBinnary source# cd ./fs/etc/rootBinnary etc# mkdir boarootBinnary etc# chmod 777 boa/rootBinnary etc# cd boarootBinnary boa# kwrite boa.conf1、Group的修改修改 Group nogroup为 Group user(开发板上有的组)修改 User nobody为 User bo
21、a (user组中的一个成员)根据你的开发板的情况设定。一定要存在的组和用户。以下是我在开发板上的操作:rootlocalhost s#adduser -g user boaChanging password for boaEnter the new password (minimum of 5, maximum of 8 characters)Please use a combination of upper and lower case letters and numbers.Enter new password:Bad password: too short.Warning: weak
22、password (continuing).Re-enter new password:passwd820: password for boa changed by user rootPassword changed.root#2、ScriptAlias的修改修改 ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/为 ScriptAlias /cgi-bin/ /var/www/cgi-bin/这是在设置CGI的目录,你也可以设置成别的目录。比如用户文件夹下的某个目录。3、ServerName的设置修改 #ServerName www.your.org.here为
23、ServerName www.your.org.here注意:该项默认为未打开,执行Boa会异常退出,提示“gethostbyname:No such file or directory”,所以必须打开。其它默认设置即可。你也可以设置为你自己想要的名字。比如我设置为:ServerName binnary2410此外,还需要:将mime.types文件复制/etc目录下,通常可以从linux主机的 /etc目录下直接复制即可。(以下配置和boa.conf的配置有关)创建日志文件所在目录/var/log/boa创建HTML文档的主目录/var/www创建CGI脚本所在录 /var/www/cgi-
24、binrootBinnary log# mkdir -m 777 boarootBinnary log# cd .rootBinnary var# mkdir -m 777 wwwrootBinnary var# mkdir -m 777 www/cgi-binrootBinnary var# cd .rootBinnary rootfs# cp /etc/mime.types etc/三、运行Boa开发板操作:root#boa如果发现boa没有运行,则可以在开发板的/var/log/boa/error_log文件中找原因。比如端口已被其他程序占用: root#cat /var/log/boa
25、/error_log20/Feb/2008:21:21:57 +0000 boa.c:194 - unable to bind: Address already in use或是用户设置错误等等,都可以查到。四、功能测试静态网页测试将静态网页存入根文件系统的/var/www目录下(可以将主机 /usr/share/doc/HTML/目录下的index.html、homepage.css和img、stylesheet-images目录复制到/var/www目录下)在根文件系统的/var目录下 rootBinnary var# cp /usr/share/doc/HTML/index.html w
26、ww/rootBinnary var# cp -r /usr/share/doc/HTML/img www/rootBinnary var# cp /usr/share/doc/HTML/homepage.css www/rootBinnary var# cp -r /usr/share/doc/HTML/stylesheet-images www/直接在浏览器中输入开发板的IP地址(比如我的是http:/192.168.10.240) ,出现linux的欢迎网页。静态HTML调试成功。CGI功能测试1、编写HelloworldCGI.c程序rootBinnary source$ vi hel
27、loworldCGI.c(主程序的程序开头一定要用Tab,而不是空格,不然编译可能不通过)#include#includeint main(void)printf(Content-type: text/htmlnn);printf(n);printf(CGI Outputn);printf(n);printf(Hello,world.n);printf(n);printf(n);exit(0);2.交叉编译生成CGI程序 rootBinnary source$ /armtools/bin/arm-linux-gcc -o helloworldCGI helloworldCGI.c将hellow
28、orldCGI 拷贝至根文件系统的/var/www/cgi-bin/下rootBinnary source$ cp helloworldCGI ./nfs/rootfs/var/www/cgi-bin/3.测试浏览器输入 http:/192.168.10.240/cgi-bin/helloworldCGI 网页出现 Hello,world. 调试成功!附录资料:从 XML 生成可与 Ajax 共同使用的 JSON时下,非常流行使用 JavaScript 代码为数据驱动的 Web 应用程序添加互动性。若能将数据编码成 JavaScript Object Notation(JSON)的格式,您就可
29、以更轻松地通过 JavaScript 语言使用它。通过本文,发掘使用 XSLT V2 从 XML 数据生成 JSON 的几种不同方法。几年前,许多开发人员很看好 XML、XSLT、Extensible HTML (XHTML)和其他一些基于标记的语言。现在,Asynchronous JavaScript and XML(AJAX)成了新的热点,人们又将目光转向了使用 JavaScript 代码的数据驱动的富 Internet 应用程序。但是开发人员是否已经消除了 XML 和这一新技术之间的鸿沟呢?当然,您可以在 Web 客户机中使用 XML 解析器来读取数据,但这种做法会带来两个问题。第一,出
30、于安全方面的原因,XML 数据只能从与此页面相同的那个域中读取。这虽然不是什么大的限制因素,但它的确会引起部署方面的问题,还会阻碍 DHTML 小部件的创建。第二,读取和解析 XML 会非常慢。另一种做法是让服务器执行 XML 的解析工作,方法是设置服务器,使之向浏览器发送以 JavaScript 代码或时下流行的 JavaScript Object Notation(JSON)编码的数据。本文将展示如下三种使用 XSLT V2 语言和 Saxon XSLT V2 处理器从 XML 数据生成 JSON 的技巧: l 简单编码 l 通过函数调用加载数据 l 编码对象 JSON 简介要学习如何将数
31、据编码成 JSON(它只是 JavaScript 的一个子集),最好的方法是从数据开始。清单 1 显示了书籍列表的一个示例 XML 数据集。清单 1. 基本的图形化图书馆 Code Generation in Action JackHerrington Manning PHP Hacks JackHerrington OReilly Podcasting Hacks JackHerrington OReilly 这个数据集很简单,只包含三本书,每本书都具有惟一的 ID、书名、作者姓名及出版商的名字。(没错,我只选择了我自己的书作为数据集,但能怨我吗?这些书实在是不可多得的节日和生日礼物。)清单
32、 2 显示了这些数据在 JSON 中的效果。清单 2. JSON 中的示例数据集 id: 1, title: Code Generation in Action, first: Jack, last: Herrington, publisher: Manning , . 方括号 () 表明这是一个数组。大括号 () 则表明这是一个散列表,该散列表由一组名称和值对组成。在本例中,我创建了一个散列表的数组 用来存储这类结构式数据的一种常见方法。另外一点值得注意的是字符串是通过单引号或双引号被编码的。所以,如果我想用单引号编码 OReilly,我就必须使用反斜杠对它进行转义:OReilly。 这让我
33、编写的这个 XSLT 样式表更为有趣了一些。我并未在本例中放上任何日期,但您也可以通过如下两种方法来编码日期。第一种方法是将日期作为字符串,该字符串必须在后面被解析。第二种方法是将日期作为一个对象,比如:publishdate: new Date( 2006, 6, 16, 17, 45, 0 )这段代码将 publishdate 的值设置为6/16/2006 5:45:00 p.m.。简单编码接下来我将陆续介绍 JSON 编码的几种技巧。第一种也是其中最简单的一种,此样式表如 清单 3 所示。清单 3. simple.xsl 样式表 var g_books = 1, id: ,name: ,
34、first: ,last: ,publisher: ;要理解此样式表,不妨先来看一下 清单 4 所示的输出。清单 4. simple.xsl 的输出var g_books = id: 1,name: Code Generation in Action,first: Jack,last: Herrington,publisher: Manning, id: 2,name: PHP Hacks,first: Jack,last: Herrington,publisher: OReilly, id: 3,name: Podcasting Hacks,first: Jack,last: Herring
35、ton,publisher: OReilly;这里,我将名为 g_books 的变量设置为一个包含三个散列表的数组,每个散列表包含关于该书的信息。再回过头来看看 清单 3,您会发现第一个模板匹配 / 路径,它也是首先应用到输入数据集的模板,该模板使用 for-each 循环来遍历每本书。之后,它使用 标记来将文本从该数据输出到 JavaScript 输出代码。对于字符串,我使用名为 js:escape() 的定制函数,它在模板之前定义。该函数使用一个正则表达式将一个单引号标记更改为带有反斜杠的单引号标记。最后一个重要的元素是 标记,它告知处理器要输出的是文本而不是 XML。要检验此过程是否可以
36、正常工作,我加入了一个 simple .html 文件,该文件引用我在 simple.js 保存的 XSL 样式表的输出。这个 HTML 文件如 清单 5 所示。清单 5. simple.html 文件Simple JS loaderdocument.write( Found +g_books.length+ books );.html 文件使用 标记简单地加载已编码了的 JavaScript 代码。之后,第二个 标记将数组的长度写出到浏览器页面,如 图 1 所示。图 1. simple.html 的输出好了!数据文件包含三本书,相应的 JavaScript 文件也包含三本书。它真的可以工作!
37、通过函数加载上述第一个示例很简单,而且在大多数情况下可以发挥其作用,但它存在一些问题。第一个问题是对于数据何时被加载没有任何提示。如果数据是像页面那样被静态加载的,这不成问题。但是如果页面动态创建了一个 标记来按需加载数据,那么就很有必要知道 标记是何时完成的。实现此功能的最好的方法是让编码了的数据调用一个 JavaScript 函数,而不是只设置数据。这个概念很重要,所以我将花一些时间来介绍一下为什么您必须要通过动态生成的 标记来加载数据。页面加载后,从服务器获得数据是 Web 2.0 的核心功能。一种方法是使用 AJAX 机制通过到服务器的调用来加载 XML。然而,出于安全性的原因,AJA
38、X 机制只限于从单一域获取数据。这在大多数情况下都没有问题,但有时,您可能需要 JavaScript 代码运行在他人的页面上(例如,Google Maps)。在这种情况下从服务器获得数据的惟一方法是通过动态加载 标记。获悉 标记何时加载的最好的方法是让 标记返回的脚本调用函数而不是简单地加载数据。清单 6 显示了在函数调用中编码的数据。清单 6. Function1.jsAddBooks( id: 1,name: Code Generation in Action,first: Jack,last: Herrington,publisher: Manning, id: 2,name: PHP
39、Hacks,first: Jack,last: Herrington,publisher: OReilly, id: 3,name: Podcasting Hacks,first: Jack,last: Herrington,publisher: OReilly );清单 7 给出了相应的 .html 文件。清单 7. Function1.htmlFunction 1 JS loadervar g_books = ;function AddBooks( books ) g_books = books; drawbooks( g_books );稍后将详细介绍 drawbooks 函数。这里重要的是了解一下页面如何定义 AddBooks 函数,该函数随后会由 function1.js 文件中的脚本调用。该 AddBooks 函数负责处理数据。而且被调用的 AddBooks 函数会向页面指示 标记被正确加载,并已加载完成。要创建