基於HTTP協議實現的小型web服務器 雲服務


咱們先了解一下這個項目最終能達到的一個目標,而後以這個來進行項目的分析:  html

这里写图片描述

GET方法使用的是帶參數的URL,即傳遞的參數會使用?鏈接在資源路徑後邊;POST方法使用的是不帶參數的URL,它的參數是經過http請求報頭中的請求消息體傳遞給服務器的。
sql

这里写图片描述響應報頭中的狀態碼和狀態碼描述,例如:當請求的資源不存在時,會收到「404 NotFound」的頁面,404就是狀態碼,「NotFound」就是狀態碼描述,即請求的文件不存在。
shell

2、服務器實現的基本思路

一、http協議是基於TCP通訊的協議,所以,實現web服務器的第一步至少要能實現兩個主機不一樣進程之間的TCP通訊。  數據庫

二、接下來的部分就是比較主要的處理邏輯了,當服務器收到請求後,首先應該分析請求方法(由於web服務器是要支持cgi的,但請求方法不一樣處理cgi也不一樣,這裏咱們只處理GET和POST方法)。  瀏覽器

三、當方法肯定後,應該拿到請求的URL,這一步是爲了咱們後邊能處理GET和POST方法的cgi(GET和POST的參數位置不一樣,GET的參數在URL中,POST的參數在請求正文中)  服務器

四、判斷資源是否存在,若是存在,判斷這個資源是一個目錄、普通文件仍是一個可執行程序。以前幾步咱們已經提取到URL以及參數。GET方法:若是沒有參數,就直接將請求的資源返回(即進入非cgi模式運行);不然,進入cgi模式內部運行;只要是POST方法就須要支持cgi:直接進入cgi函數內部運行。 

非cgi模式:
進入非cgi模式時必定是GET方法且沒有參數,此時進入echo_www()函數內部便可,該函數會將所請求的資源以html的格式返回給瀏覽器。

cgi模式: 

这里写图片描述

上述這張圖描述了運行cgi時的過程,首先服務器要從瀏覽器上讀取參數,而後須要fork出一個子進程進行cgi部分的處理,父進程經過環境變量的方式將參數轉交給子進程,子進程運行完成後,將結果交給父進程,父進程再將數據輸出給瀏覽器。在這個過程當中能夠將父進程看做一個所謂的中間量,只進行了參數的轉交,所以能夠將子進程的輸入輸出文件描述符進行重定向,即子進程直接與瀏覽器「聯繫」。

下面總結出父子進程內部各自須要乾的事情:

这里写图片描述

3、錯誤處理

錯誤處理這部分的實現能夠參考echo_www()函數,但須要改變響應的消息報頭的格式,即改變狀態碼,狀態碼描述,以及返回的頁面。例如當請求的資源不存在時,服務器須要返回給瀏覽器一個默認的404頁面,告訴客戶請求的資源不存在。效果如圖: 

这里写图片描述

4、項目文件

这里写图片描述

目錄: 

 cgi:運行cgi部分的實現代碼 

 conf:配置文件,存放須要綁定的服務器的ip和port 

log:shell的日誌文件以及http錯誤處理的日誌文件 

 lib:mysql須要的lib庫 

sql_client:mysql部分的API及CGI實現 

wwwroot:web服務器工做的根目錄,包含各類資源頁面(例如默認的index.html頁面,差錯處理的404頁面),以及執行cgi的可執行程序 

文件: 

configure.sh:sheel腳本,運行該shell腳本後須要自動生成Makefile文件 

http_ctl.sh:服務器控制腳本,須要實現服務器的啓動、暫停以及從新啓動 

httpd.pid:與http_ctl.sh配合使用。若是把服務器變成守護進程在後臺運行,從新啓動時就須要檢測服務器是否啓動,該文件存放服務器啓動之後的進程id  

httpd.h:服務器的方法聲明 

 httpd.c:方法實現 

 main.c:服務器的主邏輯 


5、實現結果

請求資源存在: 

这里写图片描述

運行cgi後: 

这里写图片描述

6、源碼:

https://github.com/lybb/Linux/tree/master/httpd

附: 

 這裏是我遇到的一些問題,粘出來,也多是你遇到的問題:

一、本地環回測試ok,Linux下的瀏覽器測試也能夠,但不能接外部的瀏覽器訪問(沒有設置橋接模式)嗯~要是在外部瀏覽器測試的話千萬別忘記關閉防火牆 

二、服務器應答時,沒有將html格式的頁面發送,而是將底層的實現代碼展現在瀏覽器,而且在調試時將原本要打印的調試信息會打印到網頁上(在迴應空行時將send指望發送的數值寫的太大,原本只須要發送兩個字節的內容) 解決:先檢查代碼,思路正確,在容易出現問題的地方加入調試信息,最後將問題定位在echo_www()函數內 

三、不能顯示圖片(這個問題是沒有將全部發送的狀況考慮徹底,只考慮到目錄、可執行程序,但沒有考慮到若是請求的是一個路徑明確的普通文件) 解決:測試請求一個路徑明確的test.html文件,加入調試信息 ,將問題定位在:若是請求的資源存在,應該如何處理。對於普通文件,找到後並回顯給瀏覽器;若是是目錄,應答的是默認頁面;若是是可執行程序,執行後返回結果 

四、能顯示圖片後,但顯示的不完整(緣由:echo_www中,指望讀取一行信息的line值過小,不能存下一張圖片) 

五、運行cgi模式時,每次提交數據並進行submit後都會自動出現提醒下載的頁面 緣由:在響應報頭中,將Content-Type中的」text」寫成」test」。而瀏覽器對於不能識別或解析的實體,都會提醒用戶下載。

相關文章
相關標籤/搜索