基于BOA搭建及移植web服务器
这学期的硬件课设选择了web服务器。在web服务器中,较为常用的是tomcat,nigix。但是这种服务器比较大,占用资源比较多,并不适合于嵌入式设备中。而boa是一个很轻便的web服务器,部署简单,占用资源少,支持多种语言。
一、下载及配置BOA服务器
1. 下载安装boa服务器
ubuntu下操作:首先在http://www.boa.org下载BOA服务器的源码:boa-0.94.13.tar.gz版本为0.94.13。
对其进行解压:
$ tar xzf boa-0.94.13.tar.gz
还要安装必要的工具bison,flex。否则会出现:
make: yacc:命令未找到
make: *** [y.tab.c] 错误 127。
$ sudo apt-get install bison flex
打开解压出的文件夹
2. 修改相关配置文件
修改src/compat.h文件:
打开compat.h找到这一条语句:
#define TIMEZONE_OFFSET(foo) foo##->tm_gmtoff
将其修改为:
#define TIMEZONE_OFFSET(foo) (foo)->tm_gmtoff
这是由于本机所使用的交叉编译版本对语句用法的不同。
修改 src/log.c文件。
打开log.c注释掉下列语句:
/*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。
修改src/boa.c文件。
打开src/boa.c注释掉下面两句话:
#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 0
if (setuid(0) != -1) {
DIE(”icky Linux kernel bug!”);
}
#endif
否则会出现问题:
boa.c:228 - icky Linux kernel bug!: No such file or directory。
3. 生成boa可执行文件
进入相关目录生成makefile文件:
$ cd boa-0.94.13/src
$ ./configure
修改makefile文件。
$vim Makefile
修改CC = gcc
为 CC = arm-linux-gnueabihf-gcc
修改CPP = gcc -E
为 CPP = arm-linux-gnueabihf-gcc -E
接下来进行编译。
$ make
然后为刚刚生成的二进制文件boa瘦身删除其调试信息。
$ arm-linux-gnueabihf-strip boa
4. 修改配置
找到配置文件boa.conf并进行如下修改:
$ sudo 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/ /www/cgi-bin/
(这里是配置服务器读取cgi程序的目录,需要在SD卡中同样的位置建立同样的目录)。
(4)对DoucmentRoot的修改
将DoucmentRoot /var/www
修改为DoucmentRoot /www
(这里是服务器初始网页放置的位置同样需要在SD卡同样的位置建立同样的文件夹并将名为index.html的网页放置在其中)。
(5)对ServerName的修改
将#ServerName [www.your.org.here](http://www.your.org.here)
修改为 ServerName www.your.org.here
否则会出现错误“gethostbyname::No such file or directory”
(6)对AccessLog修改
将AccessLog /var/log/boa/access_log(在SD卡相应位置建立同名文件夹以存放日志文件,否则提示找不到文件夹,这里不用log功能就注释掉)。
修改为#AccessLog /var/log/boa/access_log
否则会出现错误提示:“unable to dup2 the error log: Bad file descriptor”
在目标板(这里使用树莓派)上需要做的配置:
创建目录/etc/boa并且把boa 和 boa.conf拷贝到这个目录下:
先把文件从虚拟机中拖拽到物理机上,再通过vnc viewer的文件传输功能下载到板子上。用户权限无法查看根目录的文件,使用root权限进行下面操作。
$ mkdir /etc/boa
$ cp boa.conf /rootfs/etc/boa
创建HTML文档的主目录/www:
$ mkdir /www
创建CGI脚本所在的目录 /www/cgi-bin:
$ mkdir /www/cgi-bin
这样boa的服务器基础就搭建好了。
二、 测试服务器动态网页功能
到此为止服务器已经搭建完成了,接下来就要测试服务器是否能够成功运行动态网页了,为了顺利完成测试,首先要做的是让目标板和主机能够通信。
用交叉网线连接主机和开发板的配置较复杂,本地连接要使主机和开发板在同一网段下。折腾失败过一次没再研究。这里使用笔记本和树莓派wifi连在同一路由器下可直接连通,用手机热点效果一样,ping路由器后台查到的ip即可。ping通就可以通信了
接下来要做的就是编译一个cgi程序,因为只是测试用所以就用最简单的hello world来测试:
首先编写hello world代码:
#include<stdio.h>
int main(int argc, char** argv)
{
printf("Content-type:text/html\n\n");
printf("<html>\n");
printf("<head><title>cgiCHello.c</title></head>\n");
printf("<body>\n");
printf("<h1>Hello World! <font color=\"blue\">\"CGI C\"</font> </h1>\n");
printf("</body>\n");
printf("</html>\n");
return 0;
}
编写完成后将文本文档命名为:hello.c。然后再对其进行编译,使之成为一个cgi文件:
arm-linux-gnueabihf-gcc -o hello.cgi hello.c
安装交叉编译器
这里才发现自己的ubuntu没有安装交叉编译器,先在arm-linux-gnueabihf官网 下载压缩包
(1) 拷贝gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf.tar到ubuntu目录下
(2) 在/usr/local/下建立arm文件夹 mkdir /usr/local/arm
(3) 进入gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf.tar所在的目录,将gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf.tar解压到/usr/local/arm/下
tar xvf -C/usr/local/arm/
(4) 添加环境变量 vim /etc/profile
在末尾添加
export PATH=$PATH:/usr/local/arm/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
(5) source /etc/profile
使新添加的环境变量生效
(6) 查看是否安装成功
终端输入arm-linux-gnueabihf-gcc -v
出现一系列说明,末尾的版本号与安装版本相同则安装成功
代码的编辑编译可以在树莓派上进行,完全版系统镜像自带gcc
gcc -o hello.cgi hello.c
在当前文件夹下便会生成hello.cgi,为这个文件添加权限,使其可执行:
chmod +X hello.cgi
将这个文件移动到服务器中的文件夹:
cp hello.cgi /www/cgi-bin/
现在可以打开浏览器在地址栏中输入 板子ip/cgi-bin/hello.cgi 出现下图所示页面说明cgi功能可以使用,可以进行下一步工作了:
实现嵌入式web远程控制功能
目前为止,服务器的搭建以及数据的传输等基本功能已经实现了,为了能够实现嵌入式web远程控制的功能,就需要让控制者进入到其主页来进行编辑提交,所以在这个页面中就要让控制者能够对目标板进行各种控制和修改,而html只是单方向的,不能进行信息的交互,这时候就需要cgi程序来完成交互的任务。
一、静态网页的配置
服务器的文件结构:/www为服务器根目录,存放index.html是服务器的首页,cgi-bin文件夹存放各种cgi程序和sh脚本,下面每个编译好的.cgi和.sh文件都cp到这个目录下。
html文件的格式:
编辑index.html,文件的内容如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Hello</title>
<script type="text/javascript">
function MM_jumpMenu(targ,selObj,restore){ //v3.0
eval(targ+".location='"+selObj.options[selObj.selectedIndex].value+"'");
if (restore) selObj.selectedIndex=0;
}
</script>
</head>
<body>
<h1>Hello</h1>
<p> </p>
<p> </p>
<form id="form1" name="form1" method="get" action="/cgi-bin/reboot.cgi">
<input type="submit" value="重启">
</form>
<a href="http://192.168.43.133/cgi-bin/hello.cgi#tips" target="_blank">hello~</a><pre>
<form action="/cgi-bin/Changeip.cgi" method="post">
<input type="text" name="var_ip">
<input type="submit" >
</form>
</p>
</html>
每个标记都是一一对应的。每个网页文件都是以<html>开始和以</html>结束。<title>与</title>之间的内容是网页的标题。会显示在浏览器的标题栏上。<body>与</body>之间放的是网页内容。
显示出的效果如下:
<p> </p>
语句能够实现空行功能,以便使网页整体结构不会过于紧凑,
<a href="http://192.168.43.133/cgi-bin/hello.cgi#tips" target="_blank">hello~</a><pre>
该语句表示了在网页中加入一个超链接,该链接指向http://192.168.43.133/cgi-bin/hello.cgi 显示为hello用于测试服务器的cgi功能。
点击hello~之后服务器跳转,页面显示的内容:
二、动态网页的配置
1 HTML表单
<form action="/cgi-bin/Changeip.cgi" method="post"> /表单动作指向Changeip.cgi 传送方式为post
<input type="text" name="var_ip"> /插入文本框,赋值名为var_ip
<input type="submit" > /插入提交按钮
</form> /表单结束
上面的语句表示了以post的方式将表单内容发送给Changeip.cgi,同时定义了一个按键和一个输入文本框,按钮的属性为提交按钮,文本框内的值为var_ip的值。
2 cgi功能的实现
为了能够实现更改ip的的功能就需要写一个shell脚本调用配置文件并对其进行修改,然而修改这个文件需要root权限,可是单单给shell脚本加上权限并不能达到目的,这时就需要借用一个c程序来提升其权限:
Changeip.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("Content-type: text/html\n\n"); //输出类型
uid_t uid ,euid;
uid = getuid() ;
euid = geteuid();
if(setreuid(euid, uid))
perror("setreuid"); //交换这两个id
system("/www/cgi-bin/Changeip.sh"); //调用程序
return 0;
}
这个c程序所做的便是提升changip.sh脚本的权限。当在网页中输入一个ip地址后,进入changip.sh
将通过awk截取变量2)的值,并赋值给var_ip这个变量:
var_ip=`echo $QUERY_STRING | awk -F '&' '{print $1}' | awk -F '=' '{print $2}'`
因为采用wlan连接,设置静态ip地址不是在interfaces里,而是在/etc/dhcpcd.conf中更改。
将得到的var_ip这个值写入/etc/dhcpcd.conf:
eth0_cfg="/etc/dhcpcd.conf"
sed -i '/^static ip_address=/d' $eth0_cfg #删除匹配到ip的行
echo "static ip_address=$var_ip/24" >> $eth0_cfg
这样就完成了ip的更改
Changip.sh:
#!/bin/bash
if [ $REQUEST_METHOD = "POST" ]; then
QUERY_STRING=`cat /dev/stdin`
fi
echo "Content-type:text/html"
echo ""
eth0_cfg="/etc/dhcpcd.conf"
var_ip=`echo $QUERY_STRING | awk -F '&' '{print $1}' | awk -F '=' '{print $2}'`
sed -i '/^static ip_address=/d' $eth0_cfg
echo "static ip_address=$var_ip/24" >> $eth0_cfg
使开发板重启功能也是通过cgi调用sh脚本实现。
仿照Changeip编写如下代码:
reboot.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("Content-type: text/html\n\n");
printf("<html>\n");
printf("<head><title>reboot</title></head>\n");
printf("<body>\n");
printf("<h1>The system is going to reboot .......\n\n </h1>\n");
printf("</body>\n");
printf("</html>\n");
uid_t uid ,euid;
uid = getuid() ;
euid = geteuid();
if(setreuid(euid, uid))
perror("setreuid");
system("/www/cgi-bin/reboot.sh");
return 0;
}
reboot.sh:
#!/bin/bash
echo "Content-type:text/html"
echo "系统将要重启!"
/sbin/shutdown -r now
经过后面的测试shell脚本可以使用,前提是需要使用命令chmod 777 reboot.sh改变其权限。
(这里修改为u+s无效,待解)
编译Change.c和reboot.c,将.cgi和.sh文件都cp到/www/cgi-bin下
三、测试远程控制功能
1.查看boa服务
boa配置好后一般随开机启动
ps -aux | grep boa
可以查看boa的进程号,kill进程号关闭,boa
命令重启。
[图片上传失败...(image-18196d-1574346259273)]
<center>启动boa服务器
在主机浏览器地址栏内输入开发板服务器的ip(192.168.43.133)这样就进入了服务器的主页,主页的内容很直接,两个按钮,一个超链接,一个文本框:
<img src = 'https://ftp.bmp.ovh/imgs/2019/11/6d68e263bace4c21.png' />
<center>boa服务器主页
2.测试修改ip
首先设置板子的静态ip
vim /etc/dhcpcd.conf
在文件末尾添加静态地址配置
interface wlan0
static routers=192.168.1.1
static domain_name_servers=114.114.114.114 8.8.8.8
static ip_address=192.168.43.133/24
重启wifi网卡
wpa_cli -i wlan0 reconfigure
查看开发板当前ip地址,输入ifconfig wlan0
或ip addr show wlan0
命令后可以看到板子当前的连接,硬件地址,ipv4和ipv6地址,广播地址,以及子网掩码等。
在网页文本框输入想要修改的ip地址点击提交,正常弹出网页后ifconfig wlan0
查看板子ip,这时并没有更改,查看dhcpcd.conf文件,发现已经修改成功,因为更改conf文件后要再次重启wifi网卡,发现远程登陆断开,以新ip登陆,这时查看ip已经改变为刚才输入的地址了。
3.测试重启功能
在网页上点击重启按钮,弹出窗口,远程连接断开,板子灯表示正在重启,等待一会恢复连接。
总结
通过这次课设第一次搭建服务器,了解服务器文件的结构和运行方式,学到了更多linux下的命令,遇到问题多查官方文档和其他个人博客,踩到的雷前人一般都有解决方法。对于boa和cgi程序有了初步了解,尤其是权限问题,cgi和sh脚本经常提高权限才能正常运行。