最近抓了一些網路設備的open source來trace,發現有些網路設備的web UI有用到AJAX,也就是在他網頁原始碼可以很清楚看到onreadystatechange所指到的回呼函式,小弟在trace完大部份的code以後,簡單整理如下

CGI 原理解說

CGI為一通訊轉換的界面供Client與Server交換它們的資料流,client的資料(如POST的DATA,或QUERY STRING)進來時,會被CGI轉換成STREAM型態的資料並送到STDIN供SERVER讀取,同樣的,Server寫在stdout的資料同樣會被CGI轉換成資料(or 封包)的形態丟給client
讀取

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;
    }
}
最後修改日期: 3 6 月, 2022

作者

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。