實現一個http伺服器需要怎樣進行?需要哪些知識呢?

肯定已經有了一些成熟的處理流程或者方案什麼的,挺感興趣的,想了解一下~


只談 Linux 下。

  1. 直接用現成的,Apache / Nginx,python -m SimpleHTTPServer

  2. 用庫寫基本的,Python 的 HTTPServer / CGIHTTPServer 等

  3. 用 C 從底層手寫:POSIX API, Sockets,RFC 2616 。基本的單線程迭代阻塞處理;然後是高級點的優化
    1. I/O multiplexing (select / poll, epoll)
    2. 進程、線程分派模型:one-request-per-child / one-request-per-thread
    3. 非阻塞 I/O,edge trigger
  4. 高級功能
    1. 性能優化:
      1. Memory caching
      2. I/O 優化 如 文件系統選擇、Linux AIO 等。單這塊往下看文件系統、I/O 調度和其它 OS 內核細節,就可以挖非常深
      3. TCP/IP 優化
    2. CGI / FastCGI / WSGI / AJK 等後端協議支持
    3. HTTPS 協議支持
    4. 模塊化,擴展模塊支持,這塊更偏向於架構設計。Apache 就有非常出名的動態模塊設計
    5. 集群支持

3 只要看看 APUE / UNP 即可,

4 需要廣泛研究不同的代碼和各種技術的文檔。

RFC 2616: Hyper Text Transfer Protocol HTTP/1.1 http://www.w3.org/Protocols/rfc2616/rfc2616.html

UNP: Unix Network Programming, vol.1 http://book.douban.com/subject/1756533/

APUE: Advanced Programming in the Unix Environment http://book.douban.com/subject/2284230/

TCP/IP Illustrated http://book.douban.com/subject/1741925/

相對更入門的:

Advanced Linux Programming

http://www.advancedlinuxprogramming.com/

zh-cn: http://sourceforge.net/apps/trac/elpi/wiki/ALP


既然想實現一個http伺服器,首先必須要熟悉的就是http協議知識,然後在選擇具體的模塊來完成實現。下面先了解一些http協議知識,然後我們再一步一步來實現它。

http協議知識

一、 網路通信簡介

傳輸層及其以下的機制由內核提供,應用層由用戶進程提供,應用程序對通訊數據的含義進行解釋,而傳輸層及其以下處理通訊的細節,將數據從一台計算機通過一定的路徑發送到另一台計算機。應用層數據通過協議棧發到網路上時,每層協議都要加上一個數據首部(header),稱為封裝(Encapsulation)。

假設現在應用層協議為http,那麼其中的Data 可以看作是一個http請求或者應答,Data包含真正的消息正文和app首部(即報頭等)。

參考:http://blog.csdn.net/jnu_simba/article/details/8957242

二、HTTP協議詳解之請求篇

http請求由三部分組成,分別是:請求行、消息報頭、請求正文

1、請求行以一個方法符號開頭,以空格分開,後面跟著請求的URI和協議的版本,格式如下:Method Request-URI HTTP-Version CRLF
其中 Method表示請求方法;Request-URI是一個統一資源標識符;HTTP-Version表示請求的HTTP協議版本;CRLF表示回車和換行(除了作為結尾的CRLF外,不允許出現單獨的CR或LF字元)。

請求方法(所有方法全為大寫)有多種,各個方法的解釋如下:
GET 請求獲取Request-URI所標識的資源
POST 在Request-URI所標識的資源後附加新的數據
HEAD 請求獲取由Request-URI所標識的資源的響應消息報頭
PUT 請求伺服器存儲一個資源,並用Request-URI作為其標識
DELETE 請求伺服器刪除Request-URI所標識的資源
TRACE 請求伺服器回送收到的請求信息,主要用於測試或診斷
CONNECT 保留將來使用
OPTIONS 請求查詢伺服器的性能,或者查詢與資源相關的選項和需求

2、請求報頭後述
3、請求正文(略)

三、HTTP協議詳解之響應篇

在接收和解釋請求消息後,伺服器返回一個HTTP響應消息。

HTTP響應也是由三個部分組成,分別是:狀態行、消息報頭、響應正文
1、狀態行格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version表示伺服器HTTP協議的版本;Status-Code表示伺服器發回的響應狀態代碼;Reason-Phrase表示狀態代碼的文本描述。

狀態代碼由三位數字組成,第一個數字定義了響應的類別,且有五種可能取值:
1xx:指示信息--表示請求已接收,繼續處理
2xx:成功--表示請求已被成功接收、理解、接受
3xx:重定向--要完成請求必須進行更進一步的操作
4xx:客戶端錯誤--請求有語法錯誤或請求無法實現
5xx:伺服器端錯誤--伺服器未能實現合法的請求

2、響應報頭後述

3、響應正文就是伺服器返回的資源的內容

四、HTTP協議詳解之消息報頭篇

HTTP消息由客戶端到伺服器的請求和伺服器到客戶端的響應組成。請求消息和響應消息都是由開始行(對於請求消息,開始行就是請求行,對於響應消息,開始行就是狀態行),消息報頭(可選),空行(只有CRLF的行),消息正文(可選)組成。

HTTP消息報頭包括普通報頭、請求報頭、響應報頭、實體報頭。
每一個報頭域都是由名字+「:」+空格+值 組成,消息報頭域的名字是大小寫無關的。

1、普通報頭
在普通報頭中,有少數報頭域用於所有的請求和響應消息,但並不用於被傳輸的實體,只用於傳輸的消息。
Cache-Control 用於指定緩存指令,緩存指令是單向的(響應中出現的緩存指令在請求中未必會出現),且是獨立的(一個消息的緩存指令不會影響另一個消息處理的緩存機制),HTTP1.0使用的類似的報頭域為Pragma。
請求時的緩存指令包括:no-cache(用於指示請求或響應消息不能緩存)、no-store、max-age、max-stale、min-fresh、only-if-cached;
響應時的緩存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage.

Date普通報頭域表示消息產生的日期和時間

Connection普通報頭域允許發送指定連接的選項。

2、請求報頭
請求報頭允許客戶端向伺服器端傳遞請求的附加信息以及客戶端自身的信息。
常用的請求報頭
Accept
Accept-Charset
Accept-Encoding
Accept-Language
Authorization
Host(發送請求時,該報頭域是必需的)
User-Agent

3、響應報頭
響應報頭允許伺服器傳遞不能放在狀態行中的附加響應信息,以及關於伺服器的信息和對Request-URI所標識的資源進行下一步訪問的信息。
常用的響應報頭
Location
Server
WWW-Authenticate

4、實體報頭
請求和響應消息都可以傳送一個實體。一個實體由實體報頭域和實體正文組成,但並不是說實體報頭域和實體正文要在一起發送,可以只發送實體報頭域。實體報頭定義了關於實體正文(eg:有無實體正文)和請求所標識的資源的元信息。
常用的實體報頭
Content-Encoding
Content-Language
Content-Length
Content-Type
Last-Modified
Expires
GMT

五、HTTP協議相關技術補充

1、基礎:
高層協議有:文件傳輸協議FTP、電子郵件傳輸協議SMTP、域名系統服務DNS、網路新聞傳輸協議NNTP和HTTP協議等
中介由三種:代理(Proxy)、網關(Gateway)和通道(Tunnel),一個代理根據URI的絕對格式來接受請求,重寫全部或部分消息,通過 URI的標識把已格式化過的請求發送到伺服器。網關是一個接收代理,作為一些其它伺服器的上層,並且如果必須的話,可以把請求翻譯給下層的伺服器協議。一 個通道作為不改變消息的兩個連接之間的中繼點。當通訊需要通過一個中介(例如:防火牆等)或者是中介不能識別消息的內容時,通道經常被使用。
代理(Proxy):一個中間程序,它可以充當一個伺服器,也可以充當一個客戶機,為其它客戶機建立請求。請求是通過可能的翻譯在內部或經過傳遞到其它的 伺服器中。一個代理在發送請求信息之前,必須解釋並且如果可能重寫它。代理經常作為通過防火牆的客戶機端的門戶,代理還可以作為一個幫助應用來通過協議處 理沒有被用戶代理完成的請求。
網關(Gateway):一個作為其它伺服器中間媒介的伺服器。與代理不同的是,網關接受請求就好象對被請求的資源來說它就是源伺服器;發出請求的客戶機並沒有意識到它在同網關打交道。
網關經常作為通過防火牆的伺服器端的門戶,網關還可以作為一個協議翻譯器以便存取那些存儲在非HTTP系統中的資源。
通道(Tunnel):是作為兩個連接中繼的中介程序。一旦激活,通道便被認為不屬於HTTP通訊,儘管通道可能是被一個HTTP請求初始化的。當被中繼 的連接兩端關閉時,通道便消失。當一個門戶(Portal)必須存在或中介(Intermediary)不能解釋中繼的通訊時通道被經常使用。

2、協議分析的優勢—HTTP分析器檢測網路攻擊
以模塊化的方式對高層協議進行分析處理,將是未來入侵檢測的方向。
HTTP及其代理的常用埠80、3128和8080在network部分用port標籤進行了規定

3、HTTP協議Content Lenth限制漏洞導致拒絕服務攻擊
使用POST方法時,可以設置ContentLenth來定義需要傳送的數據長度,例如ContentLenth:999999999,在傳送完成前,內 存不會釋放,攻擊者可以利用這個缺陷,連續向WEB伺服器發送垃圾數據直至WEB伺服器內存耗盡。這種攻擊方法基本不會留下痕迹。

4、利用HTTP協議的特性進行拒絕服務攻擊的一些構思
伺服器端忙於處理攻擊者偽造的TCP連接請求而無暇理睬客戶的正常請求(畢竟客戶端的正常請求比率非常之小),此時從正常客戶的角度看來,伺服器失去響應,這種情況我們稱作:伺服器端受到了SYNFlood攻擊(SYN洪水攻擊)。
而Smurf、TearDrop等是利用ICMP報文來Flood和IP碎片攻擊的。本文用「正常連接」的方法來產生拒絕服務攻擊。
19埠在早期已經有人用來做Chargen攻擊了,即Chargen_Denial_of_Service,但是!他們用的方法是在兩台Chargen 伺服器之間產生UDP連接,讓伺服器處理過多信息而DOWN掉,那麼,幹掉一台WEB伺服器的條件就必須有2個:1.有Chargen服務2.有HTTP 服務
方法:攻擊者偽造源IP給N台Chargen發送連接請求(Connect),Chargen接收到連接後就會返回每秒72位元組的字元流(實際上根據網路實際情況,這個速度更快)給伺服器。

未完待續......


不建議自己實現web server, 我們部門是做CDN的, 之前有自己實現一個靜態文件server, 測試顯示性能確實比nginx還高, 但是後來功能慢慢的加, 性能就慢慢的下降,而且其中的維護成本非常高.


最簡單的http伺服器能實現如下功能即可:

1,使用socket,監聽某埠(比如80)

2,收到請求header,解析header中的地址

3,按地址取資源(可以理解為就是文件),生成響應header,把文件內容加在生成的響應header中返回


推薦一本專門講HTTP的書《HTTP: The Definitive Guide - O"Reilly Media》,看下前面幾章大概能了解HTTP的基本原理,後面的章節就比較深入了。一書在手,HTTP你有~


如果在windows server的話就有API可以用:HTTP Server API Reference (Windows) 簡單粗暴,只需要知道一點點http status code、header和cookie的知識,就可以直接上了


go語言,以下一行就可以把一個目錄指定為文件http伺服器。


看&<深入理解計算機系統&>的10-12章節,系統的I/O 、網路編程、並發編程 寫的很詳細。

1-系統的I/O 是基礎,包括打開、關閉、 讀寫文件,還有重定向;

2-網路編程介紹IP DNS socket 如何建立連接,可以結合TCP三次握手來看,socket -&>bind-&>listen-&>accept 這一個流程下來就完成已連接描述符。接下來就是你要如何處理請求的HTTP 伺服器了,書上也有例子TinyWebServer.講的很詳細,如何處理靜態和動態的內容都不錯。

3-並發編程 那就更有意思了 基於進程或者線程 select 或者是I/O復用的事件驅動,那個事件驅動的狀態圖是不是很熟悉又回到編譯原理的狀態機。然後又根據OS原理的生產者和消費者模型在寫個pool.後面寫線程模型的時候有講解信號量同步的PV操作,是不是覺得都是些很熟悉OS原理。挺有意思的~

4-然後一個簡單的 HTTP 1.0 Server 就搞定了


知道基本的Socket用法就可以寫個簡單的Web Service。然後要做的就是在這個上面添磚加瓦,建議看看《How to tomcat works》

tomcat應該比其他的web service要複雜點(個人觀點),其他的動態處理上只是做了一個轉發,tomcat要維護整個servlet的容器。


非常容易,監聽一個socket然後按照HTTP標準解析請求,然後按照HTTP標準返回一個回應,請求和回應都只是普通的二進制流而已。如果你只想無條件返回Hello World這樣的東西,事實上你連請求都不需要解析。當然這只是一個最基本的HTTP服務器。。。如果你想支持HTTP標準中所有的功能。。。。。。倒也不是很難,只是很麻煩而已,按部就班走就是了。

需要的知識:HTTP標準,相應語言的socket編程知識


http://unix4lyfe.org/gitweb/darkhttpd/blob_plain/HEAD:/darkhttpd.c


首先 要對協議了解吧,這部分查看RFC

然後 看看linux平台相關的東西,了解socket 及 各種模型編程,熟悉linux Api,建議APUE / UNP這兩本書就差不多了,到這一步的話應該是能實現一個簡單的HTTP伺服器了

再者 更深一步的就是看各種開源伺服器源碼,學習其流程架構,構建更穩定的伺服器平台


可以去看tinyhttpd的代碼,包括注釋才500行


如果有了C和數據結構基礎,要學習Linux編程很快,適合初中級開發者的《Linux高級程序設計》第三版,中文簡繁體版本各網上書城有售。 配套視頻資源:linux高級程序設計。另外,厚一點的經典之作《UNIX環境高級編程》


《深入理解計算機系統》網路編程那章有個非常好的例子,值得學習


lighttpd的代碼更簡單一點,推薦


python的話,下面這條命令就可以直接在當前目錄創建一個簡單的http文件伺服器了。代碼可以去SimpleHTTPServer.py裡面看

python -m SimpleHTTPServer


因為我們實習的時候就有過要搞HTTP伺服器,相信提問的應該也是剛接觸,樓主既然問HTTP伺服器是如何實現的,那我就詳細解釋一下,下面的內容都是自己手動實現。

伺服器基本功能要求:

  1. 伺服器框架
    1. 能夠處理並發連接請求
    2. 能夠處理超時的連接(長時間無動作的連接要刪除掉)
    3. 消息的接收
    4. 消息的發送
    5. 發送失敗或者接收失敗的異常處理

  2. HTTP協議處理模塊
    1. HTTP協議解析
    2. HTTP協議構造
  3. 可以對日誌信息的輸出
    1. 多線程
    2. 消息隊列
    3. 日誌的不同級別輸出
  4. 業務邏輯

涉及知識點:

1.並發伺服器框架

    • TCP協議
    • EPOLL 的使用(主要用來實現並發)
    • 多線程編程
    • 並發伺服器處理模型

2.HTTP協議

    • 對HTTP協議要懂

3.日誌系統

    • 信號量
    • 消息隊列

4.業務邏輯

    • 消息到手自己想怎麼處理就怎麼處理了

關於Linux的其他一些系統介面下去自己了解,整體的一些重要知識點就上面的那些。


1.自己實現一個網路庫

2.實現http協議。

3.擴展

我弄了一個簡易的(現在看來在判斷是否收到完整http請求時不太嚴謹,另外也沒有超時等其他的高級功能):

accumulation-dev/examples/httpd/httpd/http_server.cpp at master · IronsDu/accumulation-dev · GitHub


一定要用C語言實現, 其他語言實現太過於簡單了。 首先要連接HTTP協議是什麼,基礎內容是什麼, 這個可以看RFC。 然後慢慢用C語言實現吧, 實現完成了基本上把linux編程熟悉了。


推薦閱讀:

實驗室里想搭建生物信息學平台,請問是買塔式伺服器好還是刀片式的好?
雲伺服器都能用來做什麼?
ansiable和saltstack優劣勢,在百台伺服器規模下碰到的坑?
圖片伺服器應該如何設計文件結構?
求盡量詳細的主流雲伺服器體驗或者評測?

TAG:Linux | 伺服器 | HTTP |