最近抓了一些網路設備的open source來trace,發現有些網路設備的web UI有用到AJAX,也就是在他網頁原始碼可以很清楚看到onreadystatechange所指到的回呼函式,小弟在trace完大部份的code以後,簡單整理如下
CGI 原理解說
AJAX原理解說
AJAX在我觀念裡它實在很像ISR(interrupt service routine),簡單的來說,我的函式只要可以跟kernel某個事件註冊,那kernel事件發生時,會主動呼叫我的函式,AJAX也是一樣,當client要求的資料送達了,系統會主動呼叫client端註冊的資料處理函式,而不用我們人為在網頁上做refresh的動作
Client端的web頁面重點解說
<script>
var myxml
function createXMLHttpRequest() {
var xmlHttp;
if (window.XMLHttpRequest) { //if we can get XMLHttpRequest
xmlHttp = new XMLHttpRequest(); // Mozilla、Firefox、Safari
}
else if (window.ActiveXObject) { //if we can get ActiveXObject
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // Internet Explorer
}
return xmlHttp
}
function handleGetStateChange() {
if (myxml.readyState == 4) {
if (myxml.status == 200) {
//alert("Server Response" + myxml.responseText);
document.GetVal.t1.value=myxml.responseText
}
}
}
function startGetRequest()
{
myxml=createXMLHttpRequest();
if (!myxml) alert("ajax not supported")
myxml.onreadystatechange = handleGetStateChange;
myxml.open("GET", "http://192.168.15.5/cgi-bin/cpe.cgi?freq&username",true);
myxml.send("");
}
當送出的button被按下時,此程式會送出GET指令,並把freq和username這兩個參數傳送給Server,並且註冊handleGetStateChange為回呼函式
Server端的CGI處理函式如下
query_string=getenv("QUERY_STRING");
if (qlen!=0)//deal with method get
{
fprintf(stdout, "Content-Type: text/html\r\n\r\n");
for(i=0;qlen>0; i++)
{
inputs[i].val = ReadString(query_string,'&',&qlen);
repIndex=i;
query_string+=strlen(inputs[i].val)+1;
}
for (i=0;i<=repIndex;i++)
{
if (strcmp(inputs[i].val,"freq")==0) fprintf(stdout,"%s=%s&",inputs[i].val,freq);
if (strcmp(inputs[i].val,"username")==0) fprintf(stdout,"%s=%s&",inputs[i].val,username);
}
return 0;
}
Server端的cgi程式會去抓取query string並截取其內的值當做要查尋的value name
Client端web頁面完整的程式碼如下所示
<html>
<head>
<title></title>
<script>
var myxml
function createXMLHttpRequest() {
var xmlHttp;
if (window.XMLHttpRequest) { //if we can get XMLHttpRequest
xmlHttp = new XMLHttpRequest(); // Mozilla、Firefox、Safari
}
else if (window.ActiveXObject) { //if we can get ActiveXObject
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // Internet Explorer
}
return xmlHttp
}
function handleGetStateChange() {
if (myxml.readyState == 4) {
if (myxml.status == 200) {
//alert("Server Response" + myxml.responseText);
document.GetVal.t1.value=myxml.responseText
}
}
}
function handleSetStateChange() {
if (myxml.readyState == 4) {
if (myxml.status == 200) {
// alert("Server Response" + myxml.responseText);
document.SetVal.t2.value=myxml.responseText
}
}
}
function startGetRequest()
{
myxml=createXMLHttpRequest();
if (!myxml) alert("ajax not supported")
myxml.onreadystatechange = handleGetStateChange;
myxml.open("GET", "http://192.168.15.5/cgi-bin/cpe.cgi?freq&username",true);
myxml.send("");
}
function startSetRequest()
{
myxml=createXMLHttpRequest();
if (!myxml) alert("ajax not supported")
myxml.onreadystatechange = handleSetStateChange;
myxml.open("POST", "http://192.168.15.5/cgi-bin/cpe.cgi",true);
myxml.send("freq=123&username=jim");
}
</script>
</head>
<body>
<form name="GetVal">
<INPUT type="button" value="Get Value" onclick="startGetRequest()">
<INPUT type="text" name="t1">
</form>
<form name="SetVal">
<INPUT type="button" value="Set Value" onclick="startSetRequest()">
<INPUT type="text" name="t2">
</form>
</body>
</html>
Server端完整的cgi程式下所示,用gcc -o xxx.cgi xxx.c編成cgi執行檔並丟到你網頁目錄的cgi-bin下執行
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef struct {
char *name;
char *val;
} input;
FILE *fp, *fopen();
char freq[10]="1.23";
char username[10]="jemic";
char *ReadStdin(FILE *f, char stop, int *len)
{
int wsize;
char *word;
int x;
wsize = 102400;
x=0;
word = (char *) malloc(sizeof(char) * (wsize + 1));
while(1) {
word[x] = (char)fgetc(f);
if( x==wsize) {
word[x+1] = '\0';
wsize+=102400;
word = (char *)realloc(word,sizeof(char)*(wsize+1));
}
--(*len);
if((word[x] == stop) || (feof(f)) || (!(*len))) {
if(word[x] != stop) x++;
word[x] = '\0';
return word;
}
++x;
}
}
char *ReadString(char *f, char stop, int *len)
{
int wsize;
char *word;
int x;
wsize = 102400;
x=0;
word = (char *) malloc(sizeof(char) * (wsize + 1));
while(1) {
word[x] = *f;
f++;
if( x==wsize) {
word[x+1] = '\0';
wsize+=102400;
word = (char *)realloc(word,sizeof(char)*(wsize+1));
}
--(*len);
if((word[x] == stop) || (!(*len))) {
if(word[x] != stop) x++;
word[x] = '\0';
return word;
}
++x;
}
}
char *ReadData(char *line, char stop)
{
int i = 0, j;
char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));
for(i=0; ((line[i]) && (line[i] != stop)); i++)
word[i] = line[i];
word[i] = '\0';
if(line[i]) ++i;
j=0;
while(line[j++] = line[i++]);
return word;
}
int main(int argc, char *argv[])
{
input inputs[256];
register int i=0;
char *query_string=NULL;
int len=0,qlen=0,repIndex=0;
qlen=strlen(getenv("QUERY_STRING"));
query_string=getenv("QUERY_STRING");
if (qlen!=0)//deal with method get
{
fprintf(stdout, "Content-Type: text/html\r\n\r\n");
for(i=0;qlen>0; i++)
{
inputs[i].val = ReadString(query_string,'&',&qlen);
repIndex=i;
query_string+=strlen(inputs[i].val)+1;
}
for (i=0;i<=repIndex;i++)
{
if (strcmp(inputs[i].val,"freq")==0) fprintf(stdout,"%s=%s&",inputs[i].val,freq);
if (strcmp(inputs[i].val,"username")==0) fprintf(stdout,"%s=%s&",inputs[i].val,username);
}
return 0;
}
if (qlen==0)//deal with method set
{
len = atoi(getenv("CONTENT_LENGTH"));
for(i=0;len && (!feof(stdin)); i++)
{
inputs[i].val = ReadStdin(stdin,'&',&len);
inputs[i].name = ReadData(inputs[i].val,'=');
repIndex=i;
}
fprintf(stdout, "Content-Type: text/html\r\n\r\n");
for (i=0;i<=repIndex;i++)
{
if (strcmp(inputs[i].name,"freq")==0)
{
strncpy(freq,inputs[i].val,10);
fprintf(stdout,"%s=%s&",inputs[i].name,freq);
}
if (strcmp(inputs[i].name,"username")==0)
{
strncpy(username,inputs[i].val,10);
fprintf(stdout,"%s=%s&",inputs[i].name,username);
}
}
return 0;
}
else
{
fprintf(stdout, "Content-Type: text/html\r\n\r\n");
return 0;
}
}
留言