实现通过web来与其他进程交互
要像路由器那样,通过访问一个网页就能配置设备,实质上是web服务器与其他进程的通信问题。关键在于,我们的web服务器收到浏览器的请求时能够通知另外一个进程来处理。通常配置一个设备的程序可以用高级或者低级语言来实现,但是苦于不知道我们何时配置或者配置什么,而只有与用户交互的web页面知道。只要我们的web页面能够告诉我们的配置进程要配置的参数,那么问题就迎刃而解。
最简单的就是通过数据库来实现,因为web程序都支持数据库,当收到用户请求时,把要配置的参数等都写入数据库,并写入一个标志,而我们的配置进程由定时器触发不断地读取数据库,当发现标志被改了,再读取配置参数进行相应的配置。这是最简单的一种结构。
另一种就是web程序通过socket套接字与其他进程交互。socket套接字的应用广泛而且跨平台得很,只要你的网页的服务器代码能支持socket基本上就完事了,像PHP、C#等都比较好做。偏偏我只会一点c和c++....尽量找能支持c或c++的做法。果然让我找到fastCGI。官网是www.fastcgi.com。里面都有详细的介绍等。fastCGI说白了其实是实现一个main函数。在这个main函数里,没有请求的时候就阻塞,有请求的时候,函数就接着运行,通常是一个循环不断等待来自浏览器的请求。而对于每个请求,服务器以及客户端的很多信息都可以通过request的环境变量获得,例如该请求是GET还是POST等。而客户发过来的数据(例如POST)就通过标准stdin例如getchar()等得到。至于对于请求怎么响应你完全可以用熟悉的c来做。最后要返回给用户的html代码通过stdout来输出给用户。例如printf()、fprintf()等。
很多网络服务器都支持fastCGI,我使用的是在linux平台的apache服务器,一切用到的都支持跨平台。当然apache服务器太强大了,如果像路由器这样的嵌入式设备还是采取轻量级的服务器好些。apache服务器接收来自客户浏览器browser的请求,再把请求转由fastCGI进程来处理。fastCGI程序支持多种语言如perl,php,java,c,c++等,既然可以用C语言来实现,那就是说可以在fastCGI函数里面使用 socket等等等等为所欲为,通过socket,fastCGI就能于其他进程或者其他机器上的进程通信。
inux下配置apache服务器、fastCGI模块以及 fastCGI development kit
配置apache服务器的fastCGI模块花了我好几天的时间,一直在尝试把fast-dev-kit里面的例子跑起来,主要是配置问题。解压httpd-2.2.19.tar.gz(apache_http服务器)、mod_fcgid- 2.3.6(apache_http服务器的fastcgi模块)、fcgi-2.4.0(fastCGI c或c++的开发包),里面有readMe文件也有介绍。先在httpd-2.2.19下./configure默认配置.再make,make install安装好apache服务器。安装完后会在/usr/local/下出现apache2目录,在usr/local/apache/bin下启动apache服务器,./apachectl -k start。在浏览器输入localhost看apache服务器是否成功启动。接着安装mod_fcgid-2.3.6,在其目录下有个 configure.apxs文件,需要通过apache2/bin/下的apxs程序来配置,运行APX=/usr/local/apache2 /bin/apxs ./configure.apxs来配置fastCGI模块,接着make,makeinstall安装。安装完后会在apache/modules/下多了mod_fcgid.so文件,说明fastCGI模块已安装成功。fastCGI开发包同样也是./configure、make、make install安装。
用C语言实现一个fastCGI程序:
程序如下:
#include "fcgi_stdio.h"
#include <stdlib.h>
int main()
{
int count = 0;
while(FCGI_Accept() >= 0)
printf("Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI Hello!</title>"
"<h1>FastCGI Hello!</h1>"
"Request number %d running on host <i>%s</i>\n",
++count, getenv("SERVER_NAME"));
return 0;
}
当用户有请求时,FCGI_Accept()就会返回。这里的printf是fcgi_stdio.h里的printf,printf的内容会返回给用户。程序的编译需要开发包下的/libfcgi/下的fcgi_stdio.c、 fcaiapp.c、和os_unix.c。用g++来编译。还要把开发包下的include文件加入路径。编译可能会报错因为socklen_t的问题。看了os_unix.c的源代码之后你就明白了,我为求方便加了个宏定义就编译通过了。生成程序tiny.fcg。
接下来得配置apache服务器,使它可以运行我们的tiny.fcg程序。apache的服务器的配置都在/conf/下的httpd.conf文件里。
在里面添加如下信息:LoadModule fcgid_module modules/mod_fcgid.so
<Directory "/usr/local/apache2/fcgi-bin">
SetHandler fcgid-script
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
大家注意了,我之所以花了几天时间fastCGI程序都跑不起来就是因为SetHandler项,我一直写了fcgi-script!!!少了一个d。我还重装了两遍apache..最后终于让我发现了。一改为fcgid-script。。终于可以了!当访问出错的时候,apache会把错误记录在apache/logs/下的error_log和access_log,当你调试fastCGI程序的时候,这两个文件给你很大帮助。
apache的配置文件里的语法官网都有介绍,要是你配置了还跑不起来,你就得像我那样去啃官网的英文文档了看天意了。。。。
配置好后fcgi-bin文件夹里面的程序收到请求时都自动调用fastCGI来跑。假设我们里面有tiny.fcg文件。那么访问localhost/fcgi-bin/tiny.fcg时,请求就交由tiny.fcg处理了。正如我们c语言实现那样网页返回以下内容:
FastCGI Hello!
Request number 1 running on host localhost
刷新几次之后,number会变化。整个过程,我们充当一个web服务器的角色,对于用户的请求,由我们来生成html页面,然后把html源码通过printf或其他stdout返回给用户。还得熟悉下html以及javascript脚本语言这程序才好写啊。
fastCGI如何获得用户GET或者POST过来的数据
有代码有真相:先贴再解释
#include "fcgi_config.h"
#include "fcgiapp.h"
#include <sys/types.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
int main(void)
{
int rc;
FCGX_Init();
pid_t pid = getpid();
FCGX_Request request;
char *server_name;
FCGX_InitRequest(&request, 0, 0);
for (;;)
{
rc = FCGX_Accept_r(&request);
if (rc < 0)
continue;
char buffer[1024*10];
buffer[0] = '\0';
char** p = request.envp;
while(*p)
{
strcat(buffer,*p);
strcat(buffer,"\r\n");
p++;
}
server_name = FCGX_GetParam("SERVER_NAME", request.envp);
FCGX_FPrintF(request.out,
"Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI Hello!</title>"
"<h1>FastCGI Hello! </h1>"
"<p>Process %ld</p>"
"<p> host<i>%s</i></p>"
"the environments we get is: <p>"
"<pre>%s</pre>",
pid, server_name ? server_name : "?",buffer);
//
char* method = FCGX_GetParam("REQUEST_METHOD",request.envp);
if(strcmp(method,"POST") == 0)
{
char postedData[1024*10];
int dataNum = 0;
int ch;
while((ch = FCGX_GetChar(request.in)) != -1)
{
postedData[dataNum++] = (char)ch;
}
postedData[dataNum] = '\0';
FCGX_FPrintF(request.out,
"<p>the data posted is:</p>"
"<pre>%s</pre>",postedData);
}
FCGX_Finish_r(&request);
}
return 0;
}
基本上你看到函数名字大概就能猜到了,并且可以看源代码的。首先看以下 FCGX_Request的结构。
typedef struct FCGX_Request {
int requestId; /* valid if isBeginProcessed */
int role;
FCGX_Stream *in;
FCGX_Stream *out;
FCGX_Stream *err;
char **envp;
/* Don't use anything below here */
struct Params *paramsPtr;
int ipcFd; /* < 0 means no connection */
int isBeginProcessed; /* FCGI_BEGIN_REQUEST seen */
int keepConnection; /* don't close ipcFd at end of request */
int appStatus;
int nWriters; /* number of open writers (0..2) */
int flags;
int listen_sock;
} FCGX_Request;
里面的in就是stdin,可以读取由浏览器POST过来的数据。out就是输出,往out printf的内容将返回给浏览器用户。envp就是字符串数组的指针,里面保存的都是环境变量,源代码就把这些环境变量都打印出来了。把fastCGI程序(我起名为learnFCGI)放入apache服务器的fcgi-bin文件夹(已配置好)。我在浏览器访问localhost/fcgi-bin/learnCGI得到以下内容:
FastCGI Hello!
Process 12660
hostlocalhost
the environments we get is:FCGI_ROLE=RESPONDER
HTTP_HOST=localhost
HTTP_USER_AGENT=Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100626 SUSE/3.6.6-1.2 Firefox/3.6.6
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
HTTP_ACCEPT_LANGUAGE=en-us,en;q=0.5
HTTP_ACCEPT_ENCODING=gzip,deflate
HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7
HTTP_CONNECTION=close
PATH=/usr/lib64/mpi/gcc/openmpi/bin:/sbin:/usr/sbin:/usr/local/sbin:/root/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/X11R6/bin:/usr/games:/usr/lib/mit/bin:/usr/lib/mit/sbin
SERVER_SIGNATURE=
SERVER_SOFTWARE=Apache/2.2.19 (Unix) mod_fcgid/2.3.6
SERVER_NAME=localhost
SERVER_ADDR=::1
SERVER_PORT=80
REMOTE_ADDR=::1
DOCUMENT_ROOT=/usr/local/apache2/htdocs
SERVER_ADMIN=you@example.com
SCRIPT_FILENAME=/usr/local/apache2/fcgi-bin/learnFCGI
REMOTE_PORT=45762
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
REQUEST_METHOD=GET
QUERY_STRING=
REQUEST_URI=/fcgi-bin/learnFCGI
SCRIPT_NAME=/fcgi-bin/learnFCGI
由于我是直接访问的,所以即使REQUEST_METHOD为GET,QUERY_STRING也为空,另外也没有POST的数据,不妨写个简单的HTML页面测试下。
代码如下:
<html>
<body>
<form action="/fcgi-bin/learnFCGI" method="get">
name:<input type="text" name="myName" ></br>
passwrod:<input type="text" name="myPassword"></br>
<input type="submit" value="提交">
</form>
</body>
</html>
把html保存为testpage.html放在apache的usr/local/apache2/htdocs目录下。就能访问了,我这里通过localhost/testpage.html得到
往文本框里输入testname,testpassword.按提交则会转到learnFCGI程序。我们会发现,这次打印的环境变量的QUERY_STRING发生了变化:
QUERY_STRING=myName=testname&myPassword=testpassword
我们的内容提交到fastCGI程序了。
把html代码里<form> 中的method属性改为 method="post",再次运行就能看到POST数据了
REQUEST_METHOD=POST
QUERY_STRING=
REQUEST_URI=/fcgi-bin/learnFCGI
SCRIPT_NAME=/fcgi-bin/learnFCGI
the data posted is:
myName=testname&myPassword=testpassword
在使用fastCGI的过程中,网上的资料不是很多。。基本上我就去官网啃英文,啃了好几遍还的不出个怎么写法。只好去试。。最重要的是多写小程序来测试。。好像FCGX_Request里面的环境变量有什么内容本来我也不知道,那就写个程序把里面的都打印出来。。发现原来里面有个REQUEST_METHOD和QUERY_STRING选项,我就知道可以往fastCGI提交数据。并尝试把getchar()验证是否能获得POST的数据。
这样,通过fastCGI,web程序就能把数据提交给另外一个进程处理了。
实现类似路由器那样通过WEB页面配置设备
最新推荐文章于 2024-03-06 23:21:34 发布