自己寫一個Web伺服器(1)

2016-04-13    分類:作業系統、程式設計開發、首頁精華2人評論發表於2016-04-13

本文由碼農網 – 王堅原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

自己寫一個Web伺服器(1)

自己寫一個Web伺服器(2)

自己寫一個Web伺服器(3)

有天一個女人出去散步,她經過建築工地時看到三個人正在幹活。她上去問第一個人,你在幹什麼呢?第一個人覺得這問題很惱人,厲聲道,你看不到我在砌磚頭嗎?不甚滿意的女人又問第二個人他在做什麼。第二個人答道,我在砌一道磚牆。然後他看了下第一個人,喊道,嘿,你超過牆的長度了,把最後一塊磚拿下來。女人還是不滿意這個答案,他問第三個人。這個人呢,他一邊看著天一邊跟她說,我在建這世上從未有過的大教堂。在他抬頭望天的時候,另兩個人在為磚頭的對錯爭吵不休。這人轉向那兩人說,夥計們,別為那一塊磚當心了。這是個內牆,它會被粉刷沒人能看到磚頭的。把它放到另一層去吧。

這個故事的寓意是,當你知道整個系統,瞭解不同元件如何相互配合(磚,牆壁,教堂),你能快速找到和快速解決問題(磚)。

它對你從頭開始建web伺服器有什麼啟示呢?

我相信要成為好的開發者,你必須對日常使用的軟體底層系統有更好的理解,這包括程式語言,編譯器和直譯器,資料庫和作業系統,web伺服器和web框架。而為了能更好更深的理解這些系統,你必須從頭開始重建他們,從一磚一瓦開始。

老夫子有言曰:

我聽見了,我就忘了;

我看見了,我就記得了;

我做過了,我就理解了。

我希望你同意這點,我們重新建構軟體系統是學習他們怎樣運作的好方法。

在這個分為三部分的系列中,我將展示給你怎樣搭建你自己的web伺服器。我們開始吧。

簡而言之,這是一個執行在物理伺服器上的網路伺服器,它等待客戶端傳送的請求。當它收到一個請求,它會生成一個回覆並傳回到客戶端。一個客戶端和伺服器的通訊時通過HTTP協議實現。客戶端可以是你的瀏覽器或任何其他應用HTTP的軟體。

一個簡單的web伺服器是什麼樣呢?這是我給出的答案。這個例子是用Python的,但即使你不懂Python也能通過下面的程式碼和解釋理解這些概念。

import socket

HOST, PORT = '', 8888

listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
print 'Serving HTTP on port %s ...' % PORT
while True:
    client_connection, client_address = listen_socket.accept()
    request = client_connection.recv(1024)
    print request

    http_response = """\
HTTP/1.1 200 OK

Hello, World!
"""
    client_connection.sendall(http_response)
    client_connection.close()

將上面程式碼儲存為’websever1.py’,或者直接在GitHub上下載,然後想下面那樣在命令列中執行

$ python webserver1.py
Serving HTTP on port 8888 …

現在在瀏覽器位址列輸入http://localhost:8888/hello,按Enter鍵,奇蹟就發生率。你應該能在瀏覽器看到“Hello,World”,如圖所示:

看到了吧。讓我們來看看它到底是怎麼做到的。

從你鍵入的網址開始。它是一個URL下面是他的基本結構:

這是你告訴瀏覽器找尋web伺服器和連線的地址,也是你要獲取的伺服器上的頁面(路徑)。在你的瀏覽器傳送HTTP請求前,它需要和web伺服器建立一個TCP連線。然後它通過TCP連線發出HTTP請求,接著等待伺服器返回一個HTTP響應。當瀏覽器收到響應後顯示出來,在這個例子中它顯示為“Hello World!”

再來詳細看看客戶端和伺服器怎樣在HTTP請求響應之前建立TCP連線的。要做到這個,他們都用到了socket。不要直接用瀏覽器,你用telnet命令列來手動模擬瀏覽器。

在同一臺電腦上通過telnet會話執行web伺服器,指定localhost和8888埠,按下Enter:

$ telnet localhost 8888
Trying 127.0.0.1 …
Connected to localhost.

這樣你就已經跟伺服器建立了TCP連線,它執行在本地主機準備好傳送和接收HTTP訊息。下面的圖片中你可以看到伺服器必須經過一個標準的程式才可能接受一個新的TCP連線。

在同一telnet會話中鍵入GET /hello HTTP/1.1,按下Enter:

$ telnet localhost 8888
Trying 127.0.0.1 …
Connected to localhost.
GET /hello HTTP/1.1

HTTP/1.1 200 OK
Hello, World!

你剛才手動模擬了瀏覽器!你傳送了一個HTTP請求然後收到了一個HTTP響應。這就是HTTP請求的基本結構:

HTTP請求由HTTP方法(GET,因為我們要求伺服器返回給我們寫東西),路徑/hello指向伺服器的一個“頁面”和協議版本。

為了簡單的找到我們的web伺服器,這個例子完全無視上面的命令列。你可以用任何沒意義的東西替換“GET /hello HTTP/1.1”,還是會得到“Hello, World!”

一旦你輸入了請求而且按下了Enter,客戶端就像伺服器發出了請求,伺服器讀取請求,列印它然後做出適當的響應。
這是HTTP響應,伺服器傳送到你的客戶端的過程(這裡是telnet):

我們來剖析它。響應由一個狀態行 HTTP/1.1 200 OK, 接著一個空白行,然後是HTTP響應主體。

狀態行 HTTP/1.1 200 OK, 由HTTP版本,HTTP狀態程式碼和HTTP狀態程式碼指示短語 OK 組成。當瀏覽器收到響應,它顯示出響應主體,這就是為什麼你在瀏覽器中看到“Hello, World!”

這就是一個web伺服器執行的基本模型。總結起來:web伺服器建立一個監聽socket持續地接受新的連線。客戶端發起一個TCP連線,然後成功建立連線,客戶端發出一個HTTP請求給伺服器,伺服器用HTTP響應來做回覆,最後呈現給使用者。建立TCP連線的過程中客戶端和伺服器都使用了 socket。

現在你有了一個基本的伺服器,可以在瀏覽器和其他HTTP客戶端去測試。如你所見,你也可以做個人肉HTTP客戶端,用telnet同時手動鍵入hTTP請求就行。

那麼問題來了:你怎麼在你剛建立的web伺服器上執行一個Django應用,Flask應用和Pyramid應用,如何不做任何改變而適應不同的web架構呢?

我會在這個系列的第二篇告訴你。敬請關注!

譯文連結:http://www.codeceo.com/article/make-web-server-1.html
英文原文:Let’s Build A Web Server. Part 1.
翻譯作者:碼農網 – 王堅
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章