來源:http://www.linuxidc.com/Linux/2011-09/42502.htm
隨着Internet技術的興起,在嵌入式設備的管理與交互中,基於Web方式的應用成爲目前的主流,這種程序結構也就是大家非常熟悉的B/S結構,即在嵌入式設備上運行一個支持腳本或CGI功能的Web服務器,能夠生成動態頁面,在用戶端只需要通過Web瀏覽器就可以對嵌入式設備進行管理和監控,非常方便實用。本節主要介紹這種應用的開發和移植工作。
用戶首先需要在嵌入式設備上成功移植支持腳本或CGI功能的Web服務器,然後才能進行應用程序的開發。
應用:1,發佈網頁。
2,視頻監控系統設計。
3,遠程控制系統設計。1、嵌入式Web服務器移植 由於嵌入式設備資源一般都比較有限,並且也不需要能同時處理很多用戶的請求,因此不會使用Linux下最常用的如Apache 等服務器,而需要使用一些專門爲嵌入式設備設計的Web服務器,這些Web服務器在存貯空間和運行時所佔有的內存空間上都會非常適合於嵌入式應用場合。
典型的嵌入式Web服務器有Boa (www.boa.org)和thttpd (http://www.acme.com/software/thttpd/)等,它們和Apache等高性能的Web服務器主要的區別在於它們一般是單進程服務器,只有在完成一個用戶請求後才能響應另一個用戶的請求,而無法併發響應,但這在嵌入式設備的應用場合裏已經足夠了。
交叉編譯器:arm-linux-gcc version 4.3.2
平臺:s3c2440
(一) 編譯boa
從Boa的官方網站 http://www.boa.org/ 上下載了它的發行版本源碼,版本號爲0.94.13。先把源碼解壓,調出超級終端並執行:
# tar xzf boa-0.94.13.tar.gz
# cd boa-0.94.13/src
生成MakeFile文件
#./configure
修改Makefile文件,找到CC=gcc,將其改成CC=arm-linux-gcc,再找到CPP = gcc -E,將其改成CPP = arm-linux-gcc -E,並保存退出。
然後運行make進行編譯,這時出現如下錯誤:
“ util.c: 100: 1: pasting “t” and “->” does not give valid preprocessing token make ”的錯誤提示,
改動 compat.h 文件:
#define TIMEZONE_OFFSET(foo) foo##->tm_gmtoff
改爲:
#define TIMEZONE_OFFSET(foo) foo->tm_gmtoff
編譯成功。
另外,還需要修改一處src/log.c
註釋掉
if (dup2(error_log, STDERR_FILENO) == -1) {
DIE("unable to dup2 the error log");
}
爲:
/*if (dup2(error_log, STDERR_FILENO) == -1) {
DIE("unable to dup2 the error log");
}*/
否則會出現錯誤:
log.c:73 unable to dup2 the error log:bad file deor
最後優化調用交叉編譯器的strip命令將調試信息剝去,得到的最後程序只有約60KB大小。
# make
# arm-linux-strip boa
(二) 配置boa
安裝完Boa軟件後,需要對Boa進行配置,其配置文件是boa.conf,這個文件在源代碼中有,將其拷貝到嵌入式Linux根文件系統的/etc/boa目錄下。然後對這個文件幾個重要的地方進行如下修改[2]。
#[3]監聽的端口號,缺省都是80,不做修改
Port 80
# 調用的IP地址,註釋掉,這樣表明綁定到INADDR_ANY,通配於服務器的所有IP地址。不設定靜態固定的服務器地址。
#Listen 192.68.0.5
#設定那個Linux用戶組的哪個用戶,對Boa擁有權限
User root
Group root
#錯誤日誌文件。設計路徑在/dev/console下。
ErrorLog /dev/console
#訪問日誌文件。設置爲/dev/null意味關閉AccessLog功能,啓動服務器時不載入日誌文件。
AccessLog /dev/null
#服務器名字
ServerName friendly-arm
# HTML文檔的主目錄,訪問的頁面即放在這個目錄下。
DocumentRoot /www
#HTML目錄默認索引文件名。
DirectoryIndex index.html
#一個連接所允許的HTTP持續作用請求最大數目。
KeepAliveMax 1000
#HTTP持續作用中服務器在兩次請求之間等待的時間數,以秒爲單位。
KeepAliveTimeout 10
#指明mime.types[4]文件位置。
MimeTypes /etc/mime.types
#文件擴展名沒有或未知的話,使用的缺省 MIME 類型。
DefaultType text/plain
#提供 CGI 程序的 PATH 環境變量值。
CGIPath /bin:/usr/bin:/usr/sbin:/sbin
#指明 CGI 腳本的虛擬路徑對應的實際路徑, /www/cgi-bin/ 是我的根文件系統的目錄。
ScriptAlias /cgi-bin/ /www/cgi-bin/
拷貝主機 /etc/mime.types 文件到根文件系統的 etc 目錄下。
(三) 測試與出錯處理
1 、靜態網頁測試
將一靜態網頁放置到HTML文檔的主目錄/www下,爲了方便文件名修改爲index.html,並在瀏覽器中輸入目標板ip如http://192.168.1.200將出現靜態網頁。
2、cgi測試
首先,編寫Helloworld.c程序
int main(void)
{
printf("Content-type:text/html\n\n"); //這句一定要加上
printf(" Hello,world.");
exit(0);
}
//
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Content-type: text/html\n\n");
printf("<html>\n");
printf("<head><title>CGI Output</title></head>\n");
printf("<body>\n");
printf("<h1>hello,world.</h1>\n");
printf("<body>\n");
printf("</html>\n");
exit(0);
}
交叉編譯arm-linux-gcc -o helloworld.cgi helloworld.c
將helloworld.cgi複製到/www/cgi-bin/目錄下,注意執行權限,並在瀏覽器中輸入http://192.168.1.100/cgi-bin/ helloworld.cgi即可看到相應的網頁。
(四) cgi編程
動態網頁的設計有很多方法,CGI是其中之一。Boa服務器支持cgi,這裏介紹兩種方式利用cgi完成客戶端與服務器的通信。
首先了解cgi基本原,CGI全稱是“公共網關接口”(Common Gateway Interface),HTTP服務器本地或遠程應用程序通信的一種接口,其程序須運行在網絡服務器上。在物理上,CGI是一段程序,它運行在Server上,提供同客戶端 Html頁面的接口。這樣說大概還不好理解。那麼我們看一個實際例子: 現在的個人主頁上大部分都有一個留言本。留言本的工作是這樣的:先由用戶在客戶端輸入一些信息,如名字之類的東西。接着用戶按一下“留言”(到目前爲止工作都在客戶端),瀏覽器把這些信息傳送到服務器的CGI目錄下特定的cgi程序中,於是cgi程序在服務器上按照預定的方法進行處理。在本例中就是把用戶提交的信息存入指定的文件中。然後cgi程序給客戶端發送一個信息,表示請求的任務已經結束。此時用戶在瀏覽器裏將看到“留言結束”的字樣。整個過程結束。
n CGI工作的主要流程是:
1.一個用戶請求激活一個CGI應用程序;
2.CGI應用程序將交互主頁裏用戶輸入信息提取出來;
3.將用戶輸入的信息傳給服務器主機應用程序(如數據庫查詢〕;
4.將服務器處理結果通過HTML文件返回給用戶;
5.CGI進程結束。
n HTML語言與HTML表單
HTML(超文本標記語言)是用來創建與平臺無關的超文本文檔的簡單標記語言,能夠用來標記超文本消息、郵件、文檔、超媒體、菜單選項、數據庫查詢結果以及有內嵌圖形的簡單結構文檔。HTML爲文檔編碼,包括要顯示的文本、文本如何格式化的信息、要顯示的圖片名字(不是圖片自身)、以及其他重要信息。連接到一個網頁時,Web瀏覽器(如IE)就在內存中按照HTML的結構“構造”該網頁,然後在屏幕上顯示組裝好的網頁。
通常瀏覽器只能通過HTML請求從服務器獲取靜態網頁進行瀏覽,如果用戶需要通過瀏覽器提交一些數據給服務器進行處理並返回結果以達到交互的效果則要用到HTML表單。HTML表單是用戶通過瀏覽器提交數據爲主要輸入手段,它由普通文字、標記和一些稱爲“控件”的特殊元素(如複選框、單選按鈕、菜單等)以及控件上的標籤組成。用戶通過填寫或選擇控件內容來輸入數據,最後提交給服務器進行處理。
下面是一個表單的示例:
FORM的一些參數解釋如下:
1. action指定了調用的CGI腳本
2. methed定義了表單被提交的方法。methed有兩種,GET和POST。GET是CGI默認的傳輸方法,用戶輸入的數據會附在URL之後傳給Web服務器。POST方法傳遞數據時,服務器端CGI處理程序會從中接收傳輸入數據。
3. reset的外觀和submit相似,不過一旦用戶按下它,這個form中的所有輸入值都會被清除,或者是回到初始值。
n CGI的工作機制
上一節講到瀏覽器提交數據需要用到HTML表單。那麼服務器端是如何對這些數據進行識別和處理呢,這就需要用到CGI,通過CGI可以憲成瀏覽器與WEB服務器之間的信息交互。
CGI(common gateway interface)WEB 服務器和運行在服務器端的外部程序之間的一個接口規範,按照這個規範編寫並運行的外部程序就叫做CGI程序,其目的是實現Web服務器與客戶端瀏覽器之間的動態交互。CGI程序通過由Web服務器來調用實現和WEB瀏覽器之間的交互,如下圖所示,Web服務器將WEB瀏覽器發送來的信息,傳送給CGI程序,由CGI程序進行處理,CGI程序在處理完後將響應結果再回送給Web服務器,然後由Web服務器發送到Web瀏覽器。如果需要調用其他外部應用如數據庫服務等,均由CGl程序去與外部應用進行交互.
瀏覽器與Web服務器的具體交互過程如下:
(1)客戶機使用TCP/IP協議,與服務器建立連接,發送URL請求;
(2)Web服務器到相應的目錄中調用CGI程序,使用客戶機傳遞的參數作爲CGI程序的參數,而CGI程序調用相應的外部程序完成操作;
(3)CGI程序以能被識別的格式返回處理結果給HTTP服務器;
(4)Web服務器將數據返回客戶機處理,顯示CGI執行結果。
CGI程序與Web服務器進行通信、傳遞有關參數和處理結果是通過命令行參數、標準輸出、環境變量來實現的。如下圖所示,CGI的標準輸入(STDIN)是服務器的標準輸出(STDOUT),而CGI的標準輸出則是服務器的標準輸入。客戶的請求信息通過服務器的標準輸出傳送繪CGI的標準輸入,CGI對信息進行處理後,將結果發送到它的標準輸出,也就是服務器的標準輸入,然後由服務器將處理結果發送給客戶端。這裏以boa爲例,整個通信流程圖如下所示:
同時,CGI程序可以通過環境變量獲取Web服務器傳遞過來的用戶數據,常見的環境變量有:
1. SERVER-NAME:運行CGI序爲機器名或IP地址。
2. SERVER-INTERFACE:WWW服務器的類型,如:CERN型或NCSA型。
3. SERVER-PROTOCOL:通信協議,應當是HTTP/1.0。
4. SERVER-PORT:TCP端口,一般說來web端口是80。
5. HTTP-ACCEPT:HTTP定義的瀏覽器能夠接受的數據類型。
6. HTTP-REFERER: 發送表單的文件URL。(並非所有的瀏覽器都傳送這一變量)
7. HTTP-USER-AGENT:發送表單的瀏覽器的有關信息。
8. GETWAY-INTERFACE:CGI程序的版本,在UNIX下爲 CGI/1.1。
9. PATH-TRANSLATED: PATH-INFO中包含的實際路徑名。
10. PATH-INFO:瀏覽器用GET方式發送數據時的附加路徑。
11. SCRIPT-NAME: CGI程序的路徑名。
12. QUERY-STRING:表單輸入的數據,URL中間號後的內容。
13. REMOTE-HOST:發送程序的主機名,不能確定該值。
14. REMOTE-ADDR:發送程序的機器的IP地址。
15. REMOTE-USER:發送程序的人名。
1) 利用shell腳本獲取QUERY_STRING環境變量
通常這種方式適用於使用get方法提交的表單,post方法提交的表單要通過標準輸出獲取。但是對於boa服務器兩種方式效果是一樣的,即使採用post方式url中依然能獲取相應的信息。典型的shell程序如下(友善的led測試腳本,位於/www/leds.cgi):
#!/bin/sh
type=0
period=1
case $QUERY_STRING in
*ping*)
type=0
;;
*counter*)
type=1
;;
*stop*)
type=2
;;
esac
case $QUERY_STRING in
*slow*)
period=0.25
;;
*normal*)
period=0.125
;;
*fast*)
period=0.0625
;;
esac
/bin/echo $type $period > /tmp/led-control
echo "Content-type: text/html; charset=gb2312"
echo
/bin/cat led-result.template
exit 0
網頁中將要提交的表單action設置爲leds.cgi即可。即
<td colspan="2" align="center"><form method="post" action="leds.cgi" name="LED-TEST">
這種方式通信的形式如下所示:
2) 利用cgic庫編程動態網頁
CGI的輸出包括多個頭部信息和一個數據體,兩者之間用一個空行隔開。其中必須包含一個頭部信息,如果帶有數據體,則要求有Content-type,即MIME類型。MIME爲Multipurpose Internet Mial Extension protocol的縮寫,即多用途網際郵件擴充協議,它設計的最初目的是爲了在發送電子郵件時附加多媒體數據,讓郵件客戶程序能根據其類型進行處理。當它被HTTP協議支持之後,它的意義就更爲重要了。它使得HTTP不僅能傳輸普通的文本,而且能傳輸聲音、視頻等數據。MIME類型由兩部分組成,前面是數據的大類別,後面定義具體的種類。常見的MIME類型如下表所示:
CGI程序一般由以下三部分構成:
(1)數據解碼部分:通過表單輸入、由瀏覽器傳送給服務器的數據都是經過URL編碼的,必須進行解碼。如果不需要處理表單輸入,則該部分省略。
(2)數據頭部分:必須包含這一部分作爲第一個輸出行,該行後必須有一空格行。該行可以是下列三種之一:
ü 數據類型,如:Content-type:text/html
ü 地址類型(Location),如:location://www.kernel.org
ü 狀態類型(Status),如:status:200 OK
(3)CGI程序主體部分。
對通過表單輸入的數據進行處理,並輸出到標準輸出。
綜上所述,CGI程序的功能是獲取Web服務器傳送的數據,解碼處理後,根據用戶的要求進行其它的操作。一般是生成動態Web頁面或者調用其它的應用服務。
從原理上說,CGI程序設計可以採用任何讀寫標準輸入,輸出的語言,比如C/C++、Perl、Java等。但在嵌入式系統中,C語言是一個首選的工具語言。
這裏利用設計好的一個cgic庫來進行cgi的相關操作
CGIC是一個支持CGI開發的開放源碼的標準C庫。移植比較簡單。
1、下載源碼
http://www.boutell.com/cgic/上下載源碼,當前最新版本是2.05
tar xzf cgic205.tar.gz(實際下載到的是.tar.tar,一樣)
2、修改Makefile文件
修改 CC = gcc爲 CC = /usr/local/arm/2.95.3/bin/arm-linux-gcc
修改 AR = ar爲 AR = /usr/local/arm/2.95.3/bin/arm-linux-ar
修改 RANLIB = arnlib爲 RANLIB = /usr/local/arm/2.95.3/bin/arm-linux-ranlib
修改 gcc cgictest.o -o cgictest.cgi ${LIBS}爲 $(CC) $(CFLAGS) cgictest.o -o cgictest.cgi ${LIBS}
修改 gcc capture.o -o capture ${LIBS}爲 $(CC) $(CFLAGS) capture.o -o capture ${LIBS}
3、編譯
make編譯,得到CGIC庫libcgic.a
4、驗證
將capture和cgictest.cgi複製到主機的/var/www/cgi-bin目錄下,IE輸入http://192.168.1.200/cgi-bin/cgictest.cgi,可以看到cgi的測試畫面
注意:拷貝至目標板上後,必須更改其屬性chmod 755 *
cgictest.cgi是cigic的一個例程,入口在cgimain,參考cgictest.c可以編寫出其他的動態網頁。需要注意的是fprintf("Content-type:text/html\n\n"); //這句一定要加上。