ZYNQ系列(八) ZYNQ下使用BOA

13 篇文章 8 订阅

ZYNQ系列(八) ZYNQ下使用BOA

第一章 Petalinux创建工程
第二章 Petalinux-config配置说明
第三章 QSPI自启动工程
第四章 将文件打包进文件系统
第五章 将文件打包进文件系统
第六章 ZYNQ下使用CMAKE创建APP工程
第七章 ZYNQ下使用CMAKE创建QT工程
第八章 ZYNQ下使用BOA




前言

服务器软件(BOA)始终在HTTP 端口守候客户的连接请求,当客户向服务器发起一个连接请求后,客户和服务器之间经过“三步握手”建立起连接。在接收到客户端的HTTP 请求消息后,服务器对消息进行解析,包括:读取请求URL、映射到对应的物理文件、区分客户端请求的资源是静态页面还是CGI 应用程序等。如果客户请求的是静态文件,那么服务器读取相应的磁盘文件,并将其作为HTTP响应消息中的实体返回给客户端,如果客户端请求的是CGI 应用程序,那么服务器将创建相应的CGI 应用程序进程,并将各种所需信息(客户端请求信息、服务器端相关信息等)按CGI 规范传递给CGI 应用程序进程,此后由CGI 应用程序接管控制。

CGI应用程序读取从Web 服务器传递来的各种信息,并对客户端的请求进行解释和处理,如使用SQL 语句来检索或者更新数据库,或者将从客户端获得的数据,按与被监控对象所定义的通信协议重新组帧,从UART 口发送到被监控对象。最后CGI 应用程序会将处理结果按照CGI 规范返回给Web 服务器,Web 服务器会对CGI 应用程序的处理结果进行解析,并在此基础上生成HTTP 响应信息返回给客户端。

嵌入式web服务器所要实现的功能是让客户端使用浏览器向服务器发送 HTTP请求,服务器响应客户端的请求后,并引导到指定的脚本程序,对命令进行解析,将信息交给后台——CGI去处理。CGI解析信息后,向远程设备发出控制信息。设备响应后,返回给CGI控制信息,CGI再将信息解析成变量输出到Web Server上,最后客户端得到WebServer发回的页面消息(HTML),就能得到现场设备的运行状态,实现对现场设备的远程监控。

服务器中主要包括Boa和CGI两部分,其中Boa管理着返回客户端的WEB页面,而CGI控制着客户端和服务器端的信息交换,所以我们可以通过编写相应的CGI程序来实现所需要的功能。Boa服务器的实现主要分为两步,boa服务器的移植和CGI程序的设计。CGI的程序编写包括两个部分:HTML代码和C代码;CGI程序与Boa Web服务器之间通过环境变量、命令行参数和标准输入等方式进行通信。


一、编译BOA

  1. 下载BOA源码:从www.boa.org下载boa-0.94.13.tar.gz源码

  2. 将源码放入虚拟机并解压:

     $  tar zxvf boa-0.94.13.tar.gz 
    
  3. 生成配置文件:
    方式一:没用,不知道能不能行

     $  ./configure --host=arm-linux-gnueabihf  --enable-static CC= arm-linux-gnueabihf-gcc AR= arm-linux-gnueabihf-ar LD= arm-linux-gnueabihf-ld RANLIB= arm-linux-gnueabihf-ranlib export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabihf --prefix=/home/workzc/alinx/3rdparty/libboa/
    

    方式二:
    修改Makefile文件中的交叉编译工具选项

    CC = arm-linux-gnueabihf-gcc
    CPP = arm-linux-gnueabihf-gcc -E
    LDFLAGS = -static

  4. 修改boa.c文件
    将boa.c文件中的以下内容注释
    if ( setuid ( 0 ) != - 1 ) {
    DIE ( “icky Linux kernel bug!” );
    }
    注释掉下面这段程序:
    if (passwdbuf == NULL) {
       DIE(”getpwuid”);
    }
    if(initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
    DIE(”initgroups”);
    }

  5. 修改compat.h文件
    #define TIMEZONE_OFFSET(foo) foo##->tm_gmtoff
    修改成
    #define TIMEZONE_OFFSET(foo) (foo)->tm_gmtoff

  6. 修改config.c文件
    将if(!server_name){…}内容注释,位于266-286行

  7. 修改log.c文件
    注释掉以下内容
    if (dup2(error_log, STDERR_FILENO) == -1) {
    DIE(“unable to dup2 the error log”);
    }
    不注释会报错:unable to dup2 the error log:bad file descriptor

  8. 编译

     $ make && make install
    

二、 BOA服务器配置

#1. 监听的端口
Port 8080
#2. 服务器运行的用户和组
User 0
Group 0
#3. 关闭错误日志文件
#ErrorLog /var/log/boa/error_log
#4. 关闭访问日志文件
#AccessLog /var/log/boa/access_log
#5. 设置服务器名字
ServerName www.config.rx
#6. 指明CGI脚本的虚拟路径对应的实际路径
ScriptAlias /cgi-bin/ /var/www/cgi-bin/

三、 BOA服务器文件系统修改

  1. 拷贝boa
    将boa拷贝到开发板根文件系统的/bin下
  2. 拷贝mime.types
    从linux桌面系统的etc目录拷贝mime.types文件到开发板系统的etc目录
  3. 开发板增加如下目录:
    (1)创建web服务器HTML文档的主目录/var/www
    mkdir /var/www
    (2)创建CGI脚本所在目录/var/www/cgi-bin/
    mkdir /var/www/cgi-bin
    (3)创建目录/etc/boa并且把boa.conf拷贝到这个目录下
    mkdir /etc/boa

四、 编译minixml

  1. 下载源码: https://www.msweet.org/mxml/

  2. 将源码放入虚拟机并解压:

    $  tar zxvf mxml-3.2.tar.gz 
    
  3. 生成配置文件:

     ./configure --host=arm-linux-gnueabihf --prefix=/home/workzc/alinx/3rdparty/libxml/
    
  4. 编译

     	$ make && make install
    

五、编译CGIC

  1. 下载源码: https://github.com/boutell/cgic

  2. 将源码放入虚拟机并解压:

     $ unzip cgic-master.zip
    
  3. 修改Makefile文件

CC=arm-linux-gnueabihf-gcc
AR=arm-linux-gnueabihf-ar
RANLIB=arm-linux-gnueabihf-ranlib
CFLAGS=-g -Wall -static
cgictest.cgi: cgictest.o libcgic.a
$(CC) $(CFLAGS) cgictest.o -o cgictest.cgi ${LIBS}
capture: capture.o libcgic.a
$(CC) $(CFLAGS) capture.o -o capture ${LIBS}
clean:
	rm -f *.o libcgic.a *.cgi capture cgicunittest
  1. 编译

     $  make
    

编译得到的文件

libcgic.a:CGIC库
capture:调试辅助程序
cgictest.cgi:测试程序
  1. 安装CGIC

     $  make install
    

    CGIC安装路径为:

     libcgic.a 安装在/usr/local/lib
     cgic.h 安装在/usr/local/include
    

    CGIC库安装后就可以使用CGIC编程了或者直接取出 libcgic.a, cgic.h,直接编程。

  2. CGIC文件的移植(CGIC自身的DEMO)
    将capture和cgictest.cgi拷贝到开发板的/var/www/cgi-bin目录

  3. 运行cgi程序
    在客户端浏览器运行

     http://192.168.x.xxx/cgi-bin/cgictest.cgi
    

    如果正常显示网页内容,则BOA与CGIC可以正常工作

六、 BOA CGIC使用DEMO

  1. HTML网页制作
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Test Upload</title>
    <meta name="author" content="scorpio">
    <!-- Date: 2016-07-30 -->
</head>
<body>
<form action="cgi-bin/upload.cgi" method="post" enctype="multipart/form-data" target="_blank">
    <input type="file" name="file" value="" />
    <input type="submit" name="submit" value="OK">
</form>
</body>
</html>
  1. cgi程序编程
#include <stdio.h>   
#include <string.h>   
#include <unistd.h>   
#include <fcntl.h>   
#include <sys/stat.h>   
#include "cgic.h" 
 
#define BufferLen 1024   
 
int cgiMain(void)
{   
    cgiFilePtr file;   
    int targetFile;   
    mode_t mode;   
    char name[128];   
    char fileNameOnServer[64];   
    char contentType[1024];   
    char buffer[BufferLen];   
    char *tmpStr=NULL;   
    int size;   
    int got,t;   
    cgiHeaderContentType("text/html");   
    //取得html页面中file元素的值,应该是文件在客户机上的路径名   
    if (cgiFormFileName("file", name, sizeof(name)) !=cgiFormSuccess)
    {   
        fprintf(stderr,"could not retrieve filename/n");   
        goto FAIL;   
    }   
    cgiFormFileSize("file", &size);   
    //取得文件类型,不过本例中并未使用   
    cgiFormFileContentType("file", contentType, sizeof(contentType));   
    //目前文件存在于系统临时文件夹中,通常为/tmp,通过该命令打开临时文件。临时文件的名字与用户文件的名字不同,所以不能通过路径/tmp/userfilename的方式获得文件   
    if (cgiFormFileOpen("file", &file) != cgiFormSuccess) 
        {   
        fprintf(stderr,"could not open the file/n");   
        goto FAIL;   
    }   
    t=-1;   
    //从路径名解析出用户文件名   
    while(1)
        {   
        tmpStr=strstr(name+t+1,"//");   
        if(NULL==tmpStr)   
        tmpStr=strstr(name+t+1,"/");//if "//" is not path separator, try "/"   
        if(NULL!=tmpStr)   
            t=(int)(tmpStr-name);   
        else   
            break;   
    }   
    strcpy(fileNameOnServer,name+t+1);   
    mode=S_IRWXU|S_IRGRP|S_IROTH;   
    //在当前目录下建立新的文件,第一个参数实际上是路径名,此处的含义是在cgi程序所在的目录(当前目录))建立新文件   
    targetFile=open(fileNameOnServer,O_RDWR|O_CREAT|O_TRUNC|O_APPEND,mode);   
    if(targetFile<0)
        {   
        fprintf(stderr,"could not create the new file,%s/n",fileNameOnServer);   
        goto FAIL;   
    }   
    //从系统临时文件中读出文件内容,并放到刚创建的目标文件中   
    while (cgiFormFileRead(file, buffer, BufferLen, &got) ==cgiFormSuccess)
    {   
        if(got>0)   
        write(targetFile,buffer,got);   
    }   
    cgiFormFileClose(file);   
    close(targetFile);   
    goto END;   
    FAIL:   
    fprintf(stderr,"Failed to upload");   
    return 1;   
    END:   
    printf("File %s has been uploaded",fileNameOnServer);   
    return 0;   
}

将CGIC库的cgic.c、cgic.h文件拷贝到当前目录
编译程序:

 arm-linux-gnueabihf-gcc -o upload.cgi upload.c cgic.c -static
 arm-linux-gnueabihf-strip  upload.cgi

将编译后的upload.cgi拷贝到开发板的/var/www/cgi-bin目录
将upload.html文件考内到开发板/var/www目录
在客户端浏览器访问:http://192.168.6.210/upload.html
选择要上传的文件,上传
查看开发板/var/www/cgi-bin目录,上传的文件已经存放在/var/www/cgi-bin目录

七、 需要放入开发板的文件列表

文件名称来源开发板路径
boaboa编译生成/bin
mime.types虚拟机/etc/etc
boa.conf自己编写/etc/boa
upload.html自己编写/var/www
upload.cgi自己编写/var/www/cgi-bin

八、CGIC移植过程中错误的解决

  1. html网页可以运行,CGI程序运行报错

    Boa服务器报错:cgi_header: unable to find LFLF

    客户端浏览器报错:502 Bad Gateway The CGI was not CGI/1.1 compliant.

    解决方法:静态编译cgi程序

     arm-linux-gnueabihf-gcc -o hello.cgi hello.c -static
    

九、 使用minixml保存设备配置

  1. 编写config.html
<!doctype html>
<head>
<meta http-equiv="Content-Type" content="text/html ">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache,no-store,must-revalidate">
<meta http-equiv="expires" content="0">
<title>设备配置</title>
<style type="text/css" rel="stylesheet">
  body {
    line-height: 1.6;
    color: rgba(0,0,0,.85);
    font: 14px Helvetica Neue,Helvetica,PingFang SC,Tahoma,Arial,sans-serif;
  }
  blockquote, body, button, dd, div, dl, dt, form, h1, h2, h3, h4, h5, h6, input, li, ol, p, pre, td, textarea, th, ul {
    padding: 0;
  }
  .title{
    margin: 20px 0px 30px 0px;
    text-align: center;
    font-size: 20px;
    font-weight: 600;
  }
  .sub-title{
    position: absolute;
    top: -15px;
    display: inline-block;
    left: 20px;
    padding: 0px 10px;
    background-color: #fff;
    font-size: 22px;
    font-weight: 300;
    z-index: 2;
  }
  .form-container{
    position: relative;
  }
  .form{
    position: absolute;
    width: 1000px;
    left: 50%;
    margin-left: -500px;
    padding: 40px 20px 5px 20px;
    border: #eee 1px solid;
    border-radius: 10px;
    box-sizing: border-box;
  }
  @media (min-width: 768px)  {
    .form{width: 600px; margin-left: -300px;}
  }
  @media (min-width: 992px)  {
    .form{width: 800px; margin-left: -400px;}
  }
  @media (min-width: 1200px)  {
    .form{width: 1000px; margin-left: -500px;}
  }
  @media (max-width: 768px)  {
    .form{width: 100%; margin-left: 0px; left: 0;}
  }
  .form .form-item{
    margin-bottom: 15px;
    clear: both;
  }
  .form .form-item .form-label{
    position: relative;
    display:block;
    float:left;
    width: 160px;
    padding: 8px 15px;
    height: 38px;
    line-height: 20px;
    border-width: 1px;
    border-style: solid;
    border-color: #eee;
    border-radius: 2px 0 0 2px;
    text-align: left;
    background-color: #FBFBFB;
    overflow: hidden;
    box-sizing: border-box;
  }
  .form .form-item .form-label[required]:before {
    content: '*';
    position: absolute;
    top: 11px;
    left: 7px;
    color: red;
  }

  .form .form-item .form-control{
    position: relative;
    margin-left: 160px;
    left: -1px;
  }

  .form-control input, select{
    width: 100%;
    height: 38px;
    line-height: 1.3;
    line-height: 38px\9;
    border-width: 1px;
    border-style: solid;
    border-color: #eee;
    outline: 0;
    background-color: #fff;
    border-radius: 2px;
    box-sizing: border-box;
  }
  input {
    padding-left: 10px;
  }

  button {
    box-sizing: border-box;
    outline: none;
    border: none;
    cursor: pointer;
    padding: 9px 20px 10px 20px;
    border-radius: 2px;
  }
  button[type=submit] {
    background-color: #000000;
    border: #000000 1px solid;
    color: #ffffff;
  }
  button[type=reset] {
    background-color: #FBFBFB;
    border: #eee 1px solid;
  }
</style>
<script language="javascript">
window.onload = function()
{
    if (window.XMLHttpRequest)
    {// code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp=new XMLHttpRequest();
    }
    else
    {// code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    var stamp = new Date().getTime();
    xmlhttp.open("GET","boa_book.xml?timestamp=" + stamp,false);	
    xmlhttp.send();
    xmlDoc=xmlhttp.responseXML;

    var x=xmlDoc.getElementsByTagName("item");
    for (i=0;i<x.length;i++)
    {
        var name = x[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
        var conval = x[i].getElementsByTagName("value")[0].childNodes[0].nodeValue;
		if(name == "server_ip")
		{
			document.getElementById("server_ip").value = conval;
		}
		else if(name == "server_poot")
		{
			document.getElementById("server_poot").value = conval;
		}
		else if(name == "self_ip")
		{
			document.getElementById("self_ip").value = conval;
		}
    }
}

function confirm()
{
    alert("设置成功,重启设备后新的设置才能生效!");
    return true;
}
</script>
</head>

<body>
<div class="title">设置产品参数</div>
<div class="form-container">
  <div class="form">
    <div class="sub-title">
      通信相关
    </div>
    <iframe name ="server" style ="display:none;" src=' '> </iframe>

    <form enctype="multipart/form-data" onsubmit="return confirm()" action="cgi-bin/config.cgi" method="post" target ="server">

      <div class="form-item">
        <label for="" class="form-label" required>
          Server IP地址:
        </label>
        <div class="form-control">
          <input onkeyup="value=value.replace(/[^\d{1,}\.\d{1,}|\d{1,}]/g,'')" type="text" id="server_ip" name="server_ip" maxlength="15"/>
        </div>
      </div>

      <div class="form-item">
        <label for="" class="form-label" required>
          Server 端口:
        </label>
        <div class="form-control">
          <input onkeyup="value=value.replace(/[^\d]|^[0]/g,'')" type="text" id="server_poot" name="server_poot" maxlength="5"/>
        </div>
      </div>

      <div class="form-item">
        <label for="" class="form-label" required>
          设备IP地址:
        </label>
        <div class="form-control">
          <input onkeyup="value=value.replace(/[^\d{1,}\.\d{1,}|\d{1,}]/g,'')" type="text" id="self_ip" name="self_ip" maxlength="15"/>
        </div>
      </div>

      <div class="form-item">
        <div class="form-control">
          <button style="margin-right: 10px;" type="reset">取消</button>
          <button type="submit">确认</button>
        </div>
      </div>
    </form>
  </div>
</div>
</body>

  1. 编写main.c
#include <stdio.h>   
#include <string.h>   
#include <unistd.h>   
#include <fcntl.h>   
#include <sys/stat.h>   
#include <stdlib.h>
#include "cgic.h"
#include "axi_xml.h"

int cgiMain(void)
{
    char ipadd[32] = {0};
    char *boa_book_file = BOA_BOOK_FILE;
    printf("content-type:text/html;charset=utf-8\n\n");  


    if(cgiFormString(SERVER_IP_DEFAULT_NAME,boa_item_init[SERVER_IP].value, VALUE_STR_LEN) != cgiFormSuccess)
    {
        printf("cgiFormString function ipadd failed\n\n");
        exit(-1);
    }
    printf("SERVER IP:%s\n\n",boa_item_init[SERVER_IP].value);
    if(cgiFormString(SERVER_POOT_DEFAULT_NAME, boa_item_init[SERVER_POOT].value, VALUE_STR_LEN) != cgiFormSuccess)
    {
        printf("cgiFormString function SERVER_POOT_DEFAULT_NAME failed\n\n");
        exit(-1);
    }
    printf("SERVER POOT:%s\n\n",boa_item_init[SERVER_POOT].value);

    if(cgiFormString(SELF_IP_DEFAULT_NAME, (char *)&boa_item_init[SELF_IP].value, VALUE_STR_LEN) != cgiFormSuccess)
    {
        printf("cgiFormString function SELF_IP_DEFAULT_NAME failed\n\n");
        exit(-1);
    }
    printf("SELF IP:%s\n\n",boa_item_init[SELF_IP].value);
    change_boa_node(BOA_BOOK_FILE);
}
  1. 编写xml_config.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "mxml.h"
#include "axi_xml.h"
BOA_XML boa_item_init[] = {
	{SERVER_IP_DEFAULT_NAME,	SERVER_IP_DEFAULT_VALUE},
	{SERVER_POOT_DEFAULT_NAME,	SERVER_POOT_DEFAULT_VALUE},
	{SELF_IP_DEFAULT_NAME,		SELF_IP_DEFAULT_VALUE},
};

//回调函数,修改输出的格式
const char *whitespace_cb(mxml_node_t *node,int w)
{
	char *node_name;
	node_name = mxmlGetElement(node);
	//printf(" curNode:%s; w: %d \n", node_name, w);
	if(!strcmp(node_name, "configinfo"))
	{
		if( w == MXML_WS_BEFORE_OPEN || w == MXML_WS_BEFORE_CLOSE )
		{
			return("\n");
		}
		else
		{
			return NULL;
		}
	}
	else if(!strcmp(node_name, "item"))
	{
		if( w == MXML_WS_BEFORE_OPEN || w == MXML_WS_BEFORE_CLOSE )
		{
			return("\n");
		}
		else if( w == MXML_WS_AFTER_OPEN )
		{
			return("\n\t");
		}
		else
		{
			return NULL;
		}
	}
	else if(!strcmp(node_name, "name"))
	{
		if( w == MXML_WS_AFTER_CLOSE )
		{
			return("\n\t");
		}
		else
		{
			return NULL;
		}
	}
	else
		return NULL;
	#if 0
	//只在元素开始时换行
	if (w == MXML_WS_BEFORE_OPEN	//0	/* Callback for before open tag */
	|| w == MXML_WS_AFTER_OPEN 		//1 /* Callback for after open tag */
	|| w == MXML_WS_BEFORE_CLOSE 	//2 /* Callback for before close tag */
	|| w == MXML_WS_AFTER_CLOSE		//3 /* Callback for after close tag */
	   )
		return ("\n");
	else
		return NULL;
	#endif
}

int change_boa_node(const char *boa_book_file)
{
	FILE *fp;

	char cp_cmd[100] = {0};

    mxml_node_t *xml = NULL;    /* <?xml ... ?> */
    mxml_node_t *item = NULL;   /* <node> */
    mxml_node_t *tree = NULL;   /* <tree> */
    mxml_node_t *data = NULL;  /* <data> */

    char msg_num;

    assert(boa_book_file);

    /* 创建一个新的文档的版本号 */
    xml = mxmlNewXML("1.0");
 
    tree = mxmlNewElement(xml, "configinfo");
 
 	for(msg_num = 0; msg_num < BOA_MSG_NUM;msg_num++)
 	{
 		item = mxmlNewElement(tree, "item");
		data = mxmlNewElement(item, "name");
		mxmlNewText(data, 0, boa_item_init[msg_num].name); //num节点创建文本内容
		data = mxmlNewElement(item, "value");
		mxmlNewText(data, 0, boa_item_init[msg_num].value);
 	}
    fp = fopen(boa_book_file, "w");
    mxmlSaveFile(xml, fp, whitespace_cb);
    fclose(fp);
    mxmlDelete(xml);
    sprintf(cp_cmd,"cp -rf %s %s",BOA_BOOK_FILE,BOA_BOOK_FILE_DEFAULT);
    system(cp_cmd);
	return 0;
 }
  1. 编写xml_config.h
#ifndef _AXI_XML_H_
#define _AXI_XML_H_

#define BOA_XML_NUM		2
#define NAME_STR_LEN	32
#define VALUE_STR_LEN	32

#define SERVER_IP_DEFAULT_NAME		"server_ip"
#define SERVER_POOT_DEFAULT_NAME	"server_poot"
#define SELF_IP_DEFAULT_NAME		"self_ip"

#define SERVER_IP_DEFAULT_VALUE		"192.168.1.105"
#define SERVER_POOT_DEFAULT_VALUE	"8008"
#define SELF_IP_DEFAULT_VALUE		"192.168.1.151"

#define BOA_BOOK_FILE 			"/xxx/boa/boa_book.xml"
#define BOA_BOOK_FILE_DEFAULT	"/usr/bin/boa/www/boa_book.xml"

typedef struct
{
	char name[NAME_STR_LEN];
	char value[VALUE_STR_LEN];
}BOA_XML;

typedef enum
{
	SERVER_IP,
	SERVER_POOT,
	SELF_IP,
	BOA_MSG_NUM
}BOA_MSG;
int change_boa_node(const char *boa_book_file);
extern BOA_XML boa_item_init[];
#endif
  1. 加入libcgic.a libmxml.a cgic.h mxml.h进行编译。生成config.cgi
  2. 编写boa.conf文件
Port 8080
User 0
Group 0
ServerName www.config.rx
DocumentRoot /var/www
UserDir public_htm
DirectoryIndex index.html
DirectoryMaker /usr/lib/boa/boa_indexer
KeepAliveMax 1000
KeepAliveTimeout 10
MimeTypes /etc/mime.types
DefaultType text/plain
CGIPath /bin:/usr/bin:/usr/local/bin
Alias /doc /usr/doc
ScriptAlias /cgi-bin/ /var/www/cgi-bin/

根据boa.conf的提示将文件放入开发板

cp files/boa /bin
chmod 777 /bin/boa
cp files/mime.types /etc
mkdir /var/www
cp files//config.html /var/www
cp files/boa_book.xml /var/www
mkdir /var/www/cgi-bin
cp boa_book/config.cgi /var/www/cgi-bin
chmod 777 /var/www/cgi-bin/config.cgi
mkdir /etc/boa
cp boa_book/boa.conf /etc/boa
/bin/boa &

客户端运行 http://192.168.1.100:8080/config.html,这里的IP地址就是开发板的IP地址。如果正常显示网页内容,在输入正确的数据后,点击“确定”后,查看boa_book.xml,其中存储的内容应该与用户输入的一致,则BOA与CGIC工作正常。

工程文件已经打包:boa_cgic

总结

在这里插入图片描述

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖茄子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值