嵌入式web服务器

本文介绍如何在嵌入式设备上使用Boa Web服务器实现跨平台网页控制相机的方法。主要内容包括选择合适的Web服务器、避免使用ActiveX控件的原因、采用纯HTML页面的设计思路以及利用CGI接口进行动态页面创建的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要实现在PC上通过网页控制连接到嵌入式开发板的相机。

限于开发板的环境,不能选择appche等大型web服务器,选择了boa。

要想pc端跨平台,那就不能用ActiveX控件,如果仅在windows平台上是可以的,使用这种方法,PC端要装插件。

所以我选择纯html页面。

如果仅仅是显示静态内容,那么直接把html页面放到boa的根目录下即可,但如果要创建动态页面,那就得使用cgi接口。

在嵌入式上运行的web服务器基本也都只支持cgi接口,不支持什么asp,jsp。

cgi是通用网关接口的意思,只是接口而已,能使用任何能实现输入输出的语言进行编程实现,web服务器对输入输出进行了重定向

web服务器把从网页得到的输入全部重定向输出到cgi-bin目录的cgi程序作为输入,而cgi程序的输出重定向到web服务器,通过web服务器发送到浏览器。

在嵌入式环境里现成的编程语言就是shell,c/c++,这是肯定支持的,php,python,perl也是可以支持的,但脚本语言要执行,那肯定得另外配置环境,

如同java要运行需要jre一样。

 

在这里,web服务器程序不仅要进行显示,还要控制相机,要跟相机控制程序进行通信,所以用shell不太现实,所以还是选择c语言。

用c语言首先要有两类个基本的函数要实现,一是从网页发送过来的数据中提取传递的参数,二是读写配置文件。这是在没有加入通讯功能的阶段。

借鉴别人的代码,首先是提取网页参数

头文件:

/* cgivars.h */

#ifndef _CGIVARS_H
#define _CGIVARS_H

/* method */
#define GET 0
#define POST 1


/* function prototypes */
int getRequestMethod();
char **getGETvars();
char **getPOSTvars();
int cleanUp(int form_method, char **getvars, char **postvars);

void adminCheck();


#endif /* !_CGIVARS_H */

源文件:

/* cgivars.c
* (C) Copyright 2000, Moreton Bay (http://www.moretonbay.com).
* see HTTP (www.w3.org) and RFC
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "cgivars.h"

/* local function prototypes */
char hex2char(char *hex);
void unescape_url(char *url);
char x2c(char *what);

/* hex2char */
/* RFC */
char hex2char(char *hex) {
char char_value;
char_value = (hex[0] >= 'A' ? ((hex[0] & 0xdf) - 'A') + 10 : (hex[0] - '0'));
char_value *= 16;
char_value += (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A') + 10 : (hex[1] - '0'));
return char_value;
}

/* unescape_url */
/* RFC */
void unescape_url(char *url) {
int n, k;
for(n=0, k=0;url[k];++n, ++k) {
if((url[n] = url[k]) == '%') {
url[n] = hex2char(&url[k+1]);
k += 2;
}
}
url[n] = '\0';
}


/* getRequestMethod
* retn: from_method (GET or POST) on success,
* -1 on failure. */
int getRequestMethod() {
char *request_method;
int form_method;

request_method = getenv("REQUEST_METHOD");
if(request_method == NULL)
return -1;

if (!strcmp(request_method, "GET") || !strcmp(request_method, "HEAD") ) {
form_method = GET;
} else if (!strcmp(request_method, "POST")) {
form_method = POST;
} else {
/* wtf was it then?!! */
return -1;
}
return form_method;
}


/* getGETvars
* retn: getvars */
char **getGETvars() {
int i;
char **getvars;
char *getinput;
char **pairlist;
int paircount = 0;
char *nvpair;
char *eqpos;

getinput = getenv("QUERY_STRING");
if (getinput)
getinput = strdup(getinput);

//DEBUGMSG(1, ("gin=%s\n", getinput));

/* Change all plusses back to spaces */
for(i=0; getinput && getinput[i]; i++)
if(getinput[i] == '+')
getinput[i] = ' ';

pairlist = (char **) malloc(256*sizeof(char **));
paircount = 0;
nvpair = getinput ? strtok(getinput, "&") : NULL;
while (nvpair) {
pairlist[paircount++]= strdup(nvpair);
if(!(paircount%256))
pairlist = (char **) realloc(pairlist,(paircount+256)*sizeof(char **));
nvpair = strtok(NULL, "&");
}

pairlist[paircount] = 0;
getvars = (char **) malloc((paircount*2+1)*sizeof(char **));
for (i= 0; i<paircount; i++) {
if(eqpos=strchr(pairlist[i], '=')) {
*eqpos = '\0';
unescape_url(getvars[i*2+1] = strdup(eqpos+1));
} else {
unescape_url(getvars[i*2+1] = strdup(""));
}
unescape_url(getvars[i*2] = strdup(pairlist[i]));
}
getvars[paircount*2] = 0;
for(i=0;pairlist[i];i++)
free(pairlist[i]);
free(pairlist);
if (getinput)
free(getinput);
return getvars;
}


/* getPOSTvars
* retn: postvars */
char **getPOSTvars() {
int i;
int content_length;
char **postvars;
char *postinput;
char **pairlist;
int paircount = 0;
char *nvpair;
char *eqpos;

postinput = getenv("CONTENT_LENGTH");
if (!postinput)
exit(1);
if(!(content_length = atoi(postinput)))
exit(1);
if(!(postinput = (char *) malloc(content_length+1)))
exit(1);
if (!fread(postinput, content_length, 1, stdin))
exit(1);
postinput[content_length] = '\0';

//DEBUGMSG(1, ("pin=%s\n", postinput));

for(i=0;postinput[i];i++)
if(postinput[i] == '+')
postinput[i] = ' ';

pairlist = (char **) malloc(256*sizeof(char **));
paircount = 0;
nvpair = strtok(postinput, "&");
while (nvpair) {
pairlist[paircount++] = strdup(nvpair);
if(!(paircount%256))
pairlist = (char **) realloc(pairlist, (paircount+256)*sizeof(char **));
nvpair = strtok(NULL, "&");
}

pairlist[paircount] = 0;
postvars = (char **) malloc((paircount*2+1)*sizeof(char **));
for(i = 0;i<paircount;i++) {
if(eqpos = strchr(pairlist[i], '=')) {
*eqpos= '\0';
unescape_url(postvars[i*2+1] = strdup(eqpos+1));
} else {
unescape_url(postvars[i*2+1] = strdup(""));
}
unescape_url(postvars[i*2]= strdup(pairlist[i]));
}
postvars[paircount*2] = 0;

for(i=0;pairlist[i];i++)
free(pairlist[i]);
free(pairlist);
free(postinput);

return postvars;
}

/* cleanUp
* free the mallocs */
int cleanUp(int form_method, char **getvars, char **postvars) {
int i;

if (postvars) {
for(i=0;postvars[i];i++)
free(postvars[i]);
free(postvars);
}
if (getvars) {
for(i=0;getvars[i];i++)
free(getvars[i]);
free(getvars);
}

return 0;
}


void adminCheck(){
char * userName = NULL;
char * errPage = "Location: UnauthorizedError.htm\n\n";

userName = getenv("REMOTE_USER");

if(userName == NULL) goto err;

if(!strcmp("admin",userName))
{
return;
}


err: printf("%s\n",errPage);

fflush(stdout);
exit(0);
}

 

 

读取配置文件借鉴别人的,别人的读取是从配置文件读取,而写配置则只是写进一个临时文件,写进配置文件是由实际控制相机的服务程序实现的。

我要将它改为直接将参数写进配置文件。

头文件:

#include <stdio.h>
#define MAX_LINE_LENGTH 128
struct item{
char *session;
char *key;
char *value;};
int get_value(char *filename,const char *session,const char *key,char *value);
int set_value(char *filename,const char *session,const char *key,char *value);

 源文件:

#include "parseini.h"
#include <string.h>
int get_value(char *filename,const char *session,const char *key,char *value)
{
int i,j;
FILE *fp;
char temp_line[128];
char fake_session[128], fake_key[128];
memset(temp_line, 0, MAX_LINE_LENGTH);
fp=fopen(filename,"r+");
while(fgets(temp_line, MAX_LINE_LENGTH, fp))
{
if(temp_line[0]=='[')
{
if(strstr(temp_line,session))
{
i=1; //no [
while(temp_line[i]!=']')
{
fake_session[i-1]=temp_line[i];
i++;
}
fake_session[i-1]=0;
if(!strcmp(fake_session,session))
{
memset(temp_line, 0, MAX_LINE_LENGTH);
do{
fgets(temp_line, MAX_LINE_LENGTH, fp);
if(temp_line[0]=='[')break;
if((temp_line[0]!=';')&&strstr(temp_line,key))
{
i=0;
while(temp_line[i]!='=')
{
fake_key[i]=temp_line[i];
i++;
}
fake_key[i]=0;
if(!strcmp(fake_key,key))
{
j=0;
i++;
while(temp_line[i]!='\n')
{
value[j]=temp_line[i];
i++;
j++;
}
value[j]=0;
fclose(fp);
return 1;
}

}
}while(1);
fclose(fp);
return 0;
}
}
}
}
fclose(fp);
return 0;
}
int set_value(char *filename,const char *session,const char *key,char *value)
{
FILE *fp,*temp_fp;
int i,j;
char temp_line[128];
char temp_file_name[]="/etc/temp_config.ini";
char fake_session[128], fake_key[128];
memset(temp_line, 0, MAX_LINE_LENGTH);
fp=fopen(filename,"rb");
temp_fp=fopen(temp_file_name,"w");
while(fgets(temp_line, MAX_LINE_LENGTH, fp))
{
if(temp_line[0]=='[')
{
if(strstr(temp_line,session))
{
i=1; //no [
while(temp_line[i]!=']')
{
fake_session[i-1]=temp_line[i];
i++;
}
fake_session[i-1]=0;
if(!strcmp(fake_session,session))
{
fputs(temp_line,temp_fp);
memset(temp_line, 0, MAX_LINE_LENGTH);
out: while(fgets(temp_line, MAX_LINE_LENGTH, fp))
{
if(temp_line[0]=='[')break;
if((temp_line[0]!=';')&&strstr(temp_line,key))
{
i=0;
while(temp_line[i]!='=')
{
fake_key[i]=temp_line[i];
i++;
}
fake_key[i]=0;
if(!strcmp(fake_key,key))
{
j=0;
i++;
while(value[j]!=0)
{
temp_line[i]=value[j];
i++;
j++;
}
temp_line[i]='\n';

i++;
while(temp_line[i]!=0)
{
temp_line[i]=0;
i++;
}

fputs(temp_line,temp_fp);
memset(temp_line, 0, MAX_LINE_LENGTH);
goto out;
}
}
fputs(temp_line,temp_fp);
}
}
}
}
fputs(temp_line,temp_fp);
memset(temp_line, 0, MAX_LINE_LENGTH);
}
fclose(fp);
fclose(temp_fp);
unlink(filename);
rename(temp_file_name,filename);
return 0;
}

转载于:https://www.cnblogs.com/cenglinjinran/p/4741291.html

嵌入式web服务器boa框架的基础上, 使用C语言cgi, 或者Python脚本, 结合HTML + javascript + ajax 的嵌入式web系统的开发实例 html 中使用javascritp + ajax 从C语言生成的cgi文件的get, set 一些值. boa服务器的相关配置参数说明: http://www.cnblogs.com/liuweiqiang/p/3859130.html boa安装包文件名: boa-for-hi3516a.tar.gz boa.conf 文件的保存路径: cat /etc/boa/boa.conf boa可 执行文件的路径: /usr/local/bin/boa, 可以设置为: 系统启动的时候, 这个进程自动启动 boa.conf 文件的重要参数 保存html文件的目录 DocumentRoot /www 可以将这个目录, 设置为samb共享文件夹的目录, 方便修改调试 修改完成以后, 肯定要重启boa进程的 保存python脚本, 或者C语言cgi文件的目录 ScriptAlias /cgi-bin/ /var/www/cgi-bin/ 说明: cgi-bin/ 后面的斜杠, 一定要加上 可以将这个目录, 设置为samb共享文件夹的目录, 方便修改调试 修改完成以后, 肯定要重启boa进程的 html文件文件中, 调用python脚本的时候, 指定的路径, 需要有: /cgi-bin, 比如: var url = "/cgi-bin/getuser.py"; 这个是python 或者 var url = "/cgi-bin/output.cgi"; 这个是C语言 说明: 如果发现, html文件, 修改了, 可是在浏览器中, 查看html源代码的时候, 这个代码, 还是旧的, 那么可以通过清空"IE浏览器", "360浏览器"的浏览记录 以上, javascript 可以调用python 同样, 也可以调用C语言生成的cgi文件(其实, 就是可执行文件) C语言 + Html 例子 C语言 CGI实例 http://blog.youkuaiyun.com/ajrm0925/article/details/8810342 http://blog.youkuaiyun.com/liang890319/article/details/6277900 http://blog.youkuaiyun.com/gnefniu/article/details/42432657 上传文件: http://blog.youkuaiyun.com/yu_xiang/article/details/7996670 查找文件 find . -type f -name "boa.conf" -print -mount find . -type f -name "boa" -print -mount 四、嵌入式web服务器boa的配置和使用 嵌入式web服务器boa的配置文件为boa.conf, 在boa-0.94.13目录下面,复制该文件到文件 系统的/etc/boa目录下面,打开boa.conf,修改为如下内容: Port 80 User root Group root ErrorLog /dev/console AccessLog /dev/null ServerName SoftEmbed.com DocumentRoot /www DirectoryIndex index.html KeepAliveMax 1000 KeepAliveTimeout 10 MimeTypes /etc/mime.types DefaultType text/plain CGIPath /bin:/usr/bin:/usr/local/bin ScriptAlias /cgi-bin/ /www/cgi-bin/ 几个重要配置参数如下: DocumentRoot: 存放html文档的主目录; DirectoryIndex: 默认返回的html文档; ScriptAlias:cgi脚本虚拟路径对应的实际路径,/www/cgi-bin/为cgi脚本存放的实际路径; 其他配置选项的意义请参考相关资料。 复制boa可执行文件到/usr/sbin目录中, 启动boa进程 重新制作文件系统,系统启动后,在客户端浏览器上输入开发板的ip 地址,例如: http://192.168.0.218, 就可以看到显示的测试网页了,如下图所示 CGI getenv函数的参数详解: http://www.cnblogs.com/ser0632/p/5498228.html s = getenv("环境变量名"); 取得环境变量内容 putenv改变或增加环境变量 int putenv(const char * string); setenv(改变或增加环境变量) http://www.jb51.net/article/71940.htm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值