1. 程式人生 > >stm32 web伺服器實現

stm32 web伺服器實現

最近在做stm32 web伺服器的東西,忙了一段時間終於弄完了,把這幾天關於stm32伺服器的工作記錄一下。

剛接到這個任務的時候,不知道怎麼下手,網上資料似乎不是很多,於是在下載了一個官方demo測試了一下,看了一下程式碼,不是很懂,於是繼續百度找資料,找到一個比較有用的網頁,以下是連結: 最近在做stm32 web伺服器的東西,忙了一段時間終於弄完了,把這幾天關於stm32伺服器的工作記錄一下。剛接到這個任務的時候,不知道怎麼下手,網上資料似乎不是很多,於是在下載了一個官方demo測試了一下,看了一下程式碼,不是很懂,於是繼續百度找資料,找到一個比較有用的網頁,以下是連結:http://wenku.baidu.com/link?url=SfAxsft0bXxvaoeDtSGCLlnB3yQNhofQfLwfO9l-aZmTsVy2haookGZI6VP4WGlnr26Fx_BxakWV3oMQbKl54FQyssKDy2fRxI5JnIXaPgK

其實,stm32 web伺服器與pc網頁的互動一般是以表單的方式,就兩個介面,cgi和ssi。這兩個東西我的理解是這樣的,cgi 就是pc網頁向stm32 web服務下發資訊的介面,比如我們有這樣的一個網頁:

<form method='get' action='config.cgi'>

<p><label for='ip'>ip:</label><input type='text' name='ip' value="<!--#ip-->" maxlength="1" /></p>

<p><

label for='port'>port:</label><input type='text' name='port' value="<!--#port-->" maxlength="6" />

</p><p><input type='submit' value='儲存' /></p>

</form>

如果看不懂這個網頁的話,就百度一下吧,把上面東西複製到Macromedia Dreamweaver 8軟體上就能看到是什麼頁面,上面在form就是表單,在<form></form

>裡面的內容就是表單的內容,裡面有兩個輸入框,和一個儲存按鈕,當我們點出儲存的時候就會在web伺服器裡觸發,config.cgi的介面,關於web伺服器的內容,後面再說,然後會把這個表單裡的內容下發到伺服器裡,比如會把上面ip和port輸入框中的資料發到web伺服器裡,web伺服器就能獲得想要的資料。接下來說一下ssi,我們可以拿個網路抓包軟體觀察一下,pc網頁的web伺服器的通訊過程,其實也就是pc傳送一個請求,然後web伺服器返回一組資料,這組資料就是整個網頁的內容。ssi的工作就是在這組返回的資料中嵌入一個要傳送加pc端的資料在裡面,比如剛才那個表單網頁資料,我們要顯示一些資料到ip輸入框中,怎麼辦呢?在沒有ssi介面的時候可以看到,

<p><labelfor='ip'>ip:</label><input type='text' name='ip' value="<!--#ip-->" maxlength="1" /></p>

有ssi介面時候,我們就可以利用ssi介面改變返回的內容,比如:

<p><labelfor='ip'>ip:</label><input type='text' name='ip' value="<!--#ip-->192.168.1.1" maxlength="1" /></p>

可以看到 "<!--#ip-->192.168.1.1" 這個地方是不相同的,這時返回ip輸入框是帶著資料的,這個資料將顯示在ip輸入框內。

接下來分析一下程式碼,首先看一下stm32官方http web 包裡的檔案


fsdata.c,fsdata.h,是網頁轉換成的陣列, 

fs.c, fs.h是操作fsdata.c裡面資料的一些讀寫函式

httpd.c, httpd.h函式是真正實現web伺服器的檔案

httpd_cgi_ssi.c, httpd_cgi_ssi.h 就是剛才提到的cgi, ssi介面,

一般我們只需要改動httpd_cgi_ssi.c, fsdata.c(這個檔案是makefsfile.exe生成的),

makefsfile裡面又有一些什麼檔案呢


fs資料夾是所有的網頁,fsdata.c 是用makefsfile.exe轉換得到的

下面分析一下程式碼

1. void httpd_init(void)

{
  LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n"));
#if LWIP_HTTPD_SSI
  httpd_ssi_init(); //ssi介面初始化
#endif
#if LWIP_HTTPD_CGI
  httpd_cgi_init(); //cgi介面初始化
#endif
  httpd_init_addr(IP_ADDR_ANY);  //http web 相關初始化
}

2.ssi介面 要注意的一點就是 有ssi介面的網頁要以 shtml為字尾

char const* TAGS[]={  //這裡定義了ssi標籤,

    "ip",  //ip地址 對應網頁裡的<!--#ip-->
    "sp",  //伺服器埠};

u16_t DeviceSSI_Handler(int iIndex, char *pcInsert, int iInsertLen)
{
    int len = 0;
    char buff[16];


    memset(buff,0,sizeof(buff));
    switch(iIndex)
    {
        case 0: //這個index是在陣列中的位置
            sprintf(buff,"%s",“192.168.1.1”);
            len = strlen(buff);

            memcpy(pcInsert,buff,len);// 這裡是拷貝填充在ip標籤裡的內容

            break;
        case 1:

    。。。。。。

    break;

    }

    return len;

}

3.cgi介面

//cgi介面定義

tCGI CGI_TAB[]={
    {"/login.cgi", LOGIN_CGI_Handler},
    {"/saveNet.cgi", SAVE_NET_Handler} /*這裡的cginame要和網頁表單裡的action相同<formmethod='get'action='config.cgi'>*/};

const char * SAVE_NET_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
{
    uint32_t i=0;

    for (i=0; i<iNumParams/*引數數量*/; i++)
    {
        if(strcmp(pcParam[i]/*引數名字,與網頁裡控制元件的name相同name='ip'*/,"ip") == 0) //裝置ip
        {

    printf("ip is : %s \r\n",pcValue[i]/*控制元件的值*/);
        }
        else if(strcmp(pcParam[i],"port") == 0)  
        {

    ...

}

     ......

}

cgi和ssi大概就這些內容要改的,

4.開啟網頁裡是哪一個為首頁呢?在httpd.c裡有一個數據

//這裡設定首頁顯示的html ,所以首頁就是login
const default_filename g_psDefaultFilenames[] = {
  {"/login.shtml", true },
  {"/login.ssi", true },
  {"/login.shtm", true },
  {"/login.html", false },
  {"/login.htm", false }
};

5.我們傳送ssi標籤時會把標籤一起發上去,這樣在編輯控制元件裡是會把標籤一起顯示的,比如value="<!--ip-->192.168.1.1",這不是我們想要的,怎麼讓它不傳送標籤呢,

把httpd.c裡的定義  #define LWIP_HTTPD_SSI_INCLUDE_TAG           1  //改為0就不傳送標籤

6.還有一些比較常用的巨集定義

#define LWIP_HTTPD_MAX_CGI_PARAMETERS 16    //cgi數量定義

#define LWIP_HTTPD_MAX_TAG_NAME_LEN 8       //定義tag標籤長度定義

#define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192   //定義返回tag內容長度