uhttpd的實現框架

2021-06-20 00:41:04 字數 2510 閱讀 7796

uhttpd是乙個簡單的web伺服器程式,以前沒怎麼接觸過,所以這裡主要是對web伺服器設計的一些學習總結。openwrt系統中,真正用到的(需要了解的),其實不多,主要就是cgi的處理,包括與cgi程式的資訊互動等,最後一節詳細描述一下。

http協議是目前網際網路使用最廣泛的應用層協議。其協議框架很簡單,在乙個tcp連線中,以一問一答的方式進行資訊互動。具體講,就是客戶端(如常見的瀏覽器)connect服務端的知名埠(通常是80),建立乙個tcp連線,然後傳送乙個request;伺服器端對該request解析後,發回相應的response應答,並關閉tcp連線。這就是一次互動,之後客戶端再有請求,則重複上面的過程。

互動報文格式如下圖所示:

request報文首行為request-line,其中type有get、post、head三種方式,然後最重要的是url,它告訴伺服器所請求的資源。response報文首行為response-line,其中最重要的是code,它告知客戶端響應情況(found、redirect、error等),然後跟乙個簡單的可讀的短語。

兩種報文後面具體的內容格式差不多,都是一些headers(其中冒號前的str指明header型別),然後以乙個空行標識header結束,後面是資料。對於request,只有post型別的請求需要提交資料,其它型別的是沒有資料的。response報文的資料就是url所指定的資源檔案(html、doc、gif等)。

uhttpd作為乙個簡單的web伺服器,其**量並不多,而且組織結構比較清楚。和其它網路伺服器差不多,其main函式進行一些初始化(首先parse config-file,然後parse argv),然後進入乙個迴圈,不斷地監聽,每當有乙個客戶請求到達時,則對它進行處理。

對於web伺服器,所要做的處理主要就是分析url,判斷出是file-request、cgi-request或lua-request,這主要是根據url的最前面的字串(稱為字首prefix)得出的;然後就用相應的形式進行處理。如下圖所示:

前面已提到,openwrt系統中使用的uhttpd服務,主要是用cgi方式來回應客戶請求的,下面就對這種方式詳細闡述。

由上圖紅色字所示,uh_cgi_request需要兩個二外的引數pathinfo和interpreter,其中pin是乙個struct,包含了路徑中各種有用資訊;ipr指明所用的cgi程式,因為乙個伺服器中可以有多個cgi程式。

如圖所示,docroot是伺服器的資源目錄,是為了os準確定位資源位置,由uhttpd的config檔案設定,如openwrt中為/www。後面的是client傳來的url,開頭的為cgi-prefix,也是有uhttpd的config檔案設定的,它指明serv端採用cgi處理方式,如openwrt中的為/www/cgi-bin;緊接著的是cgi的程式名,它指明了使用哪個cgi程式;再後面就是實際的path資訊了,在cgi方式中,它會被當成引數供cgi程式使用。

要執行cgi程式,首先意味著需fork出乙個子程序,並通過execl函式替換程序空間為cgi程式;其次,資料傳遞,子程序替換了程序空間後,怎麼獲得原資訊,有怎麼把回饋資料傳輸給父程序(即uhttpd),父程序又怎麼接收這些資料。

首先建立了兩個pipe,這實際上是利用af_unix協議域,建立兩個相連的socket_unix,那麼它們對映的檔案描述符(即這裡的fd[0]、fd[1])就構成了乙個pipe,且這種關係即使fork後也仍然存在,因為fork僅是增加檔案的引用次數,而os維護的file結構和socket結構都沒變,這就是父子程序間傳遞資料的方式。然後fork出乙個子程序。

子程序中首先把兩個管道的一端close,注意這僅是使得檔案引用次數變為1。由於子程序待會要excel替換,替換後rfd、wfd就不存在了,因此先把它們dup2給知名的stdin、stdout,這樣即使execl替換後,ipt->extu程式可以以此來和父程序傳遞資料。另外,execl替換後,cgi程式仍需要之前的一些引數資訊,如path_info等,這種情況下,最簡單的辦法就是setenv,把需要的引數設為環境變數。

為什麼要兩個pipe,因為子程序向父程序傳遞歸饋資料需要乙個out-pipe,而若有post資料,子程序還需要乙個in-pipe,從父程序讀取post資料。

父程序中首先也是close,同上所述。若有post資料,先從httprequest-header中得到content-length,為後面傳遞給子程序做準備。然後進入乙個迴圈(為什麼要迴圈,什麼時候退出,後面講),通過select輪詢io,超時、中斷的情況就不看了,輪詢的io乙個是reader,即從子程序讀取回饋資料,而若有post資料的話,還要另乙個io,writer,向子程序寫post資料。主要的處理就是上圖中紅色字所示,具體如下:

ConvenientBanner框架實現廣告瀏覽

xmlns android id id convenientbanner android layout width match parent android layout height 200dp canloop true 或者 中動態新增 convenientbanner mconvenientb...

實現LAMP框架

綜合實驗 1.二進位制安裝資料庫 192.168.41.102 2.安裝httpd 192.168.41.101 3.安裝frm方式編譯php 192.168.41.101 4.安裝wordpress,discuz 192.168.41.101 5.完成測試 實現多虛擬主機,乙個主機blog.mag...

實現RPC框架

什麼是rpc client端 student student call serveraddr,addage,student 1.將這個呼叫對映為call id。2.將call id,student params 序列化,以二進位制形式打包 3.把2中得到的資料報傳送給serveraddr,這需要使用...