搭個 Web 伺服器(一)
導讀 | 我相信,如果你想成為一個更好的開發者,你必須對日常使用的軟體系統的內部結構有更深的理解,包括程式語言、編譯器與直譯器、資料庫及作業系統、Web 伺服器及 Web 框架。而且,為了更好更深入地理解這些系統,你必須從頭開始,用一磚一瓦來重新構建這個系統。 |
一天,有一個正在散步的婦人恰好路過一個建築工地,看到三個正在工作的工人。她問第一個人:“你在做什麼?”第一個人沒好氣地喊道:“你沒看到我在砌磚嗎?”婦人對這個答案不滿意,於是問第二個人:“你在做什麼?”第二個人回答說:“我在建一堵磚牆。”說完,他轉向第一個人,跟他說:“嗨,你把牆砌過頭了。去把剛剛那塊磚弄下來!”然而,婦人對這個答案依然不滿意,於是又問了第三個人相同的問題。第三個人仰頭看著天,對她說:“我在建造世界上最大的教堂。”當他回答時,第一個人和第二個人在為剛剛砌錯的磚而爭吵。他轉向那兩個人,說:“不用管那塊磚了。這堵牆在室內,它會被水泥填平,沒人會看見它的。去砌下一層吧。”
這個故事告訴我們:如果你能夠理解整個系統的構造,瞭解系統的各個部件如何相互結合(如磚、牆還有整個教堂),你就能夠更快地定位及修復問題(那塊砌錯的磚)。
如果你想從頭開始創造一個 Web 伺服器,那麼你需要做些什麼呢?
我相信,如果你想成為一個更好的開發者,你 必須對日常使用的軟體系統的內部結構有更深的理解,包括程式語言、編譯器與直譯器、資料庫及作業系統、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()
將以上程式碼儲存為 webserver1.py,或者直接從 上下載這個檔案。然後,在 行中執行這個程式。像這樣:
$ python webserver1.py Serving HTTP on port 8888 …
現在,在你的網頁瀏覽器的位址列中輸入 URL: ,敲一下回車,然後來見證奇蹟。你應該看到“Hello, World!”顯示在你的瀏覽器中,就像下圖那樣:
說真的,快去試一試。你做實驗的時候,我會等著你的。
完成了?不錯!現在我們來討論一下它實際上是怎麼工作的。
首先我們從你剛剛輸入的 Web 地址開始。它叫 URL,這是它的基本結構:
URL 是一個 Web 伺服器的地址,瀏覽器用這個地址來尋找並連線 Web 伺服器,並將上面的內容返回給你。在你的瀏覽器能夠傳送 HTTP 請求之前,它需要與 Web 伺服器建立一個 TCP 連線。然後會在 TCP 連線中傳送 HTTP 請求,並等待伺服器返回 HTTP 響應。當你的瀏覽器收到響應後,就會顯示其內容,在上面的例子中,它顯示了“Hello, World!”。
我們來進一步探索在傳送 HTTP 請求之前,客戶端與伺服器建立 TCP 連線的過程。為了建立連結,它們使用了所謂“套接字socket”。我們現在不直接使用瀏覽器傳送請求,而在 行中使用 telnet 來人工模擬這個過程。
在你執行 Web 伺服器的電腦上,在命令列中建立一個 telnet 會話,指定一個本地域名,使用埠 8888,然後按下回車:
$ telnet localhost 8888 Trying 127.0.0.1 … Connected to localhost.
這個時候,你已經與執行在你本地主機的伺服器建立了一個 TCP 連線。在下圖中,你可以看到一個伺服器從頭開始,到能夠建立 TCP 連線的基本過程。
在同一個 telnet 會話中,輸入 GET /hello HTTP/1.1,然後輸入回車:
$ 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!”響應。
一旦你輸入了請求行並敲了回車,客戶端就會將請求傳送至伺服器;伺服器讀取請求行,就會返回相應的 HTTP 響應。
下面是伺服器返回客戶端(在上面的例子裡是 telnet)的響應內容:
我們來解析它。這個響應由三部分組成:一個狀態行 HTTP/1.1 200 OK,後面跟著一個空行,再下面是響應正文。
HTTP 響應的狀態行 HTTP/1.1 200 OK 包含了 HTTP 版本號,HTTP 狀態碼以及 HTTP 狀態短語“OK”。當瀏覽器收到響應後,它會將響應正文顯示出來,這也就是為什麼你會在瀏覽器中看到“Hello, World!”。
以上就是 Web 伺服器的基本工作模型。總結一下:Web 伺服器建立一個處於監聽狀態的套接字,迴圈接收新的連線。客戶端建立 TCP 連線成功後,會向伺服器傳送 HTTP 請求,然後伺服器會以一個 HTTP 響應做應答,客戶端會將 HTTP 的響應內容顯示給使用者。為了建立 TCP 連線,客戶端和服務端均會使用套接字。
現在,你應該瞭解了 Web 伺服器的基本工作方式,你可以使用瀏覽器或其它 HTTP 客戶端進行試驗。如果你嘗試過、觀察過,你應該也能夠使用 telnet,人工編寫 HTTP 請求,成為一個“人形” HTTP 客戶端。
現在留一個小問題:“你要如何在不對程式做任何改動的情況下,在你剛剛搭建起來的 Web 伺服器上適配 Django, Flask 或 Pyramid 應用呢?”
我會在本系列的第二部分中來詳細講解。敬請期待。
順便,我在撰寫一本名為《搭個 Web 伺服器:從頭開始》的書。這本書講解了如何從頭開始編寫一個基本的 Web 伺服器,裡面包含本文中沒有的更多細節。訂閱郵件列表,你就可以獲取到這本書的最新進展,以及釋出日期。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2924717/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Go學習【02】:理解Gin,搭一個web demoGoWeb
- 一起寫一個 Web 伺服器Web伺服器
- GO隨筆-搭建一個Web伺服器GoWeb伺服器
- 手寫一個最迷你的Web伺服器Web伺服器
- 小白折騰伺服器(九):一步一步搭個自己的 Composer 包伺服器
- 如何建立一個可靠穩定的Web伺服器Web伺服器
- 對 *nix WEB伺服器的一個隱藏威脅Web伺服器
- 使用Node.js原生API寫一個web伺服器Node.jsAPIWeb伺服器
- 測試同學動手搭個簡易web開發專案Web
- Vue Cli3.x搭一個專案Vue
- 手搭一個 React,Typescript,Koa,GraphQL 環境ReactTypeScript
- netty系列之:輕輕鬆鬆搭個支援中文的伺服器Netty伺服器
- 筆記:學習go語言的網路基礎庫,並嘗試搭一個簡易Web框架筆記GoWeb框架
- webpack4搭一個簡易SPA應用Web
- ngrok將本機對映為一個外網的Web伺服器Web伺服器
- 論如何在伺服器上部署一個自己的web前端專案伺服器Web前端
- 帶你搭一個SpringBoot+SpringData JPA的環境Spring Boot
- IBM宣佈搭載全新雲伺服器IBM伺服器
- Web 伺服器Web伺服器
- 如何使用 Apache Web 伺服器配置多個站點ApacheWeb伺服器
- Python web伺服器3: 靜態伺服器&併發web伺服器PythonWeb伺服器
- NET Core Kestrel部署HTTPS 一個伺服器綁一個證書 一個伺服器綁多個證書HTTP伺服器
- 百聞不如一碼!手把手教你用Python搭一個TransformerPythonORM
- 那個爆火的“夢中修煉”AI,你也能用Keras搭一個了AIKeras
- 【知識分享】常見的幾個web伺服器分享Web伺服器
- OpenLiteSpeed Web 伺服器被曝多個嚴重性漏洞Web伺服器
- 如何搭建一個簡易的 Web Terminal(一)Web
- 一起寫個 WSGI Web FrameworkWebFramework
- 一個最簡單的web componentsWeb
- 基於 Koa + Vue3!一個開源的 Linux 伺服器 Web SSH 皮膚工具!VueLinux伺服器Web
- 遊戲伺服器和web伺服器有哪些地方不一樣遊戲伺服器Web
- Web 2.0 和 Web 3.0 都是什麼意思?哪一個更好?Web
- Apache Vs Nginx哪個最適合您的 Web 伺服器?ApacheNginxWeb伺服器
- 【知識分享】五個常見的web伺服器介紹Web伺服器
- Web伺服器的原理Web伺服器
- nodejs搭建web伺服器NodeJSWeb伺服器
- node搭建web伺服器Web伺服器
- web伺服器軟體Web伺服器