吴兆芝
(南京晓庄学院 数学与信息技术学院,江苏 南京 211171)
随着计算机网络技术及嵌入式技术的不断发展,嵌入式系统的网络应用已经成为嵌入式系统应用的一个重要领域,同时网络技术也成为对嵌入式系统实施远程管理与控制的重要手段.Web服务是当前网络技术的一个重要分支,也是嵌入式系统使用最多的网络技术.鉴于嵌入式系统本身的特点,对嵌入式系统的远程管理与控制主要是通过Web服务来实现.
对绝大多数的远程管理与控制功能而言,不仅涉及到网络的通信,更涉及到对受控主机的信息采集或程序控制,而这些工作单靠Web服务器本身是很难完成的.解决的方法主要有两种:一种方法是改造Web服务器使其能够使用特定的动态网页编程语言并用这种编程语言调用受控主机的程序完成特定的任务,典型的动态网页语言有PHP、ASP、JSP等;另一种方法是使用公共网关接口CGI,Web服务器通过CGI接口规范调用受控主机的可执行程序.显然,前一种方法不适合嵌入式系统使用,所以在嵌入式系统的网络管理与控制中主要采用CGI技术实现.
本文在简要介绍CGI的原理的基础上,分析用C语言实现CGI的技术要点及实现方法.最后,通过一个实例演示C语言CGI在ARM平台远程控制中的应用.
公共网关接口CGI[1]是Web服务器的一种标准规范,用来将Web用户的请求传递给服务器的应用程序,并将接收到的数据回送给Web用户.
每当用户向Web服务器提交一个页面请求(例如,点击一个超链接或输入一个网站地址),Web服务器会将用户请求的存放在服务器上的网页返回给用户.然而,当用户提交一个带有表单(form)的请求网页时,在服务器端需要接收表单内容,必要时还要根据表单内容作必要的处理.一般来说,Web服务器并不能直接处理表单,而是把表单内容传送给服务器的一个小型应用程序,由该程序对表单数据进行处理并回送必要的确定信息.这种在Web服务器与应用程序之间往返传递数据的方法或规范称之为“公共网关接口(Common Gateway Interface)”,简称CGI.
公共网关接口CGI提供了一种将用户请求页面的数据传递给应用程序并从应用程序向用户返回信息的一致性规范.该规范与服务器应用程序所使用的操作系统无关,只要操作系统具有标准输入及标准输出能力即可,因为Web服务器与应用程序之间的通信是通过标准输入及标准输出实现的.
CGI是一种通过Web服务器实现Web用户与服务器应用程序往返传递数据的基本方法.使用CGI规范实现的服务器应用程序称之为CGI程序.一般来说,能够使用操作系统标准输入及标准输出功能的程序设计语言都可与CGI编程.常用的CGI编程语言有C、Perl、PHP等,甚至UNIX及Linux操作系统的Shell也可以实现CGI编程.鉴于嵌入式系统的特点,一般都使用C语言实现CGI编程.
CGI程序需要从Web服务器接收用户信息,对该信息进行必要处理,最后返回处理结果.根据CGI规范,CGI需要完成下列任务:
接收用户信息.用户浏览器将请求页发送给Web服务器,由Web服务器创建一个子进程,在子进程中调用CGI程序,将用户信息传递给CGI程序.传递的方式有两种:通过环境变量传递及通过标准输入/标准输出传递.
解码用户信息.用户浏览器请求页在向Web传递过程中首先被编码,以适合于使用HTTP协议在网络上传送.因此,当用户信息通过Web服务器传递给CGI程序后,CGI程序要对接收到的用户信息进行解码,将其还原成初始信息.
生成HTML网页.CGI程序的处理结果要通过Web服务器回送给用户浏览器,而用户浏览器要接收的必须是HTML网页,这就要求CGI程序能够根据程序处理结果动态生成HTML网页.
用C语言[2,3]实现CGI程序的编程,主要就是实现接收用户信息、解码用户信息和生成HTML网页这三项任务.
(1)Web服务器与CGI程序的通信.由于CGI应用程序是在Web服务器创建的子进程中被调用,因此二者之间的通信可以通过环境变量实现.
首先,Web服务器将一些关键性信息,如请求方法(GEG、POST等)、请求页类型、用户主机地址等设置为相应的环境变量.然后,在CGI程序中读取这些环境变量,即可获得Web服务器传递的信息.
在C语言程序中读取环境变量,可使用getenv()函数,例如:
getenv(“CONTENT_LENGTH”),获得表单长度.
但由于环境变量只能传递少量的短小信息,因此当用户需要向CGI程序传送大量信息时无法通过环境变量实现.
Web服务器在运行过程中采用守护进程(daemon)方式常驻内存.在创建调用CGI程序的子进程时,Web服务器在父子进程间创建两个管道,在父进程中将标准输入和标准输出分别转向到这两个管道;在子进程中将标准输入设备和标准输出设备分别转向到管道的另一端.从而使父进程的标准输出通过管道传送给子进程的标准输入,同时使子进程的标准输出转向给父进程的标准输入.父子进程使用各自的标准输入及标准输出功能通过管道实现相互通信.
Web服务器通过这种管道方式,可将用户浏览器的大量数据方便地传送给CGI程序,也可从CGI接收大量的返回数据.
例如,语句fread(form_ptr,1,i,stdin);表示CGI程序通过标准输入(stdin)从Web服务器读取i个字节数据,存放到缓冲区fomr_ptr中.
(2)用户信息的解码.根据HTTP协议的需要,用户浏览器信息在传递过程首先要对传递的数据进行变换,方法有两种:一种是将某些特定字符用另一字符替换,例如将空格符用“+”替换;另一种是将一个字符用“%XX”形式的字符串,其中XX为该字符的两位16进制ASCII码,例如“&”的16进制ASCII码为0x26,所以编码之后变成“%26”.
另外,当请求页面的方法为“POST”时,还可以通过请求页面传递多个参数,其格式为:参数1=参数值1&参数2=参数值2&参数3=参数值3…参数n=参数值n,各参数之间用“&”分隔.
CGI程序的任务是对上述编码信息进行解码将其还原.
典型的解码程序如下:
void decode(char *src,char *last, char *dest)
{
for(; src != last; src++, dest++)
if(*src == '+')
*dest = ' ';
else if(*src == '%') {
int code;
if(sscanf(src+1,“%2x”,&code)!= 1)code='?';
*dest = code;
src +=2; }
else
*dest = *src;
*dest = ' ';
*++dest = ' ';
}
其中,src及last为用户数据的起始地址及终止地址,dest为解码之后数据的起始地址.
(3) 在C语言程序中生成HTML网页.根据CGI规范,CGI程序生成的HTML网页由两部分构成:网页首部(head)及网页体(body).网页各行由CGI程序通过标准输出传递给Web服务器,最后由Web服务传递给用户浏览器.下面是一个典型的程序片段:
printf(“Status:200 ”);
printf(“Content-type: text/html ”);
printf(“ ”);
printf(“
Hello, world! ”);printf(“ ”);
其中前两行输出响应页面的网页首部,其余为网页体.不难看出,其网页体就是一个典型的HTML网页.该页面经Web服务器传递给用户浏览器,在用户浏览器上显示一个字符串:Hello, world!
CGI程序本质上是Web服务器主机上的应用程序.对于一些简单的管理与控制任务来说,可直接由CGI应用程序完成.例如,对服务器主机的远程配置、获取服务器主机系统信息、远程修改服务器数据文件等.
但由于CGI程序是由Web服务器调用执行的,而Web服务器使用的是面向连接的HTTP网络协议,所以CGI程序的功能受到一定制约,一般来说不能用来完成较复杂的操作,如远程控制等.这时可采用在CGI程序中调用主机应用程序的方法来解决.
为演示C语言CGI在嵌入式系统中的应用,笔者在Mini2440 开发板上设计了一个简单的远程控制系统,实现对ARM主机蜂鸣器的远程控制.用户通过客户端浏览器网页表单设置ARM主机蜂鸣器的振动频率,频率值为0时关闭蜂鸣器.
Mini2440开发板提供了一组arm-Linux[4]系统下的演示程序,其中包含一个蜂鸣器控制程序,运行时可通过键盘动态改变蜂鸣器振动频率,ESC键用来关闭蜂鸣器.对该程序做简单改动,可供CGI程序调用.
首先,改变其控制频率的方法,通过main函数的参数向程序传递频率值;其次,将控制程序设置成守护进程,这可通过调用daemon()函数实现;第三,将守护进程的PID存盘,从而使CGI程序能够调用kill命令终止蜂鸣器守护进程.
蜂鸣器程序主函数关键代码如下:
int main(int argc, char **argv)
{int freq =1000,pid;
FILE *fp;
if (argc > 1)
freq = atoi(argv[1]);
if (freq > 2000 || freq < 11)
freq = 1000;
open_buzzer();
set_buzzer_freq(freq);
daemon(1,0);
pid = getpid();
if ((fp = fopen(“/app/pwm/pwm.pid”, “w”)) != NULL) {
fprintf(fp, “%d”, pid);
fclose(fp);
}
while(1);
}
该系统CGI程序控制页面效果如图1.
图1 ARM主机蜂鸣器远程控制系统
C语言CGI是嵌入式系统远程控制的重要手段,笔者在多个嵌入式远程控制系统中使用C语言CGI程序,收到较好效果.对C语言CGI编程技术进行深入研究,无疑具有重要的实用意义.
参考文献:
[1][美]Andrew S.Tanenbaum.Computer Networks(Fourth Edition)[M].北京:清华大学出版社(英文影印版),2008.
[2][美]Love,R.Linux System Programming[M].南京:东南大学出版社(英文影印版),2008.
[3][美]Marc J.Rochkind.Advanced UNIX Programming[M].北京:清华大学出版社(英文影印版),2006.
[4][加]Yaghmour.K.Building Embedded Linux System,2E[M].南京:东南大学出版社(英文影印版),2009.