摘要:基于寫的極簡版。服務器是屬于被動的一方,當瀏覽器發起請求的時候,服務器才能和瀏覽器通信,在此之前,服務器都處于一個等待監聽的狀態。監聽本地端口這是一個極簡的,需要注意的是,我們僅實現了協議的部分。
基于 Python3 寫的極簡版 webserver。用于學習 HTTP協議,及 WEB服務器 工作原理。筆者對 WEB服務器 的工作原理理解的比較粗淺,僅是基于個人的理解來寫的,存在很多不足和漏洞,目的在于給大家提供一個寫 webserver 的思路。項目GitHub地址:https://github.com/hanrenguang/simple-webserver。
WEB服務器原理學過計網的同學應該都知道 HTTP協議 是在 TCP協議 之上實現的。瀏覽器與服務器之間的通信首先是建立 TCP 連接,再進行請求和響應報文的傳輸。服務器是屬于被動的一方,當瀏覽器發起請求的時候,服務器才能和瀏覽器通信,在此之前,服務器都處于一個等待監聽的狀態。
socket連接實現服務器的第一步是建立一個 socket 連接,socket 套接字是對 TCP/UDP協議 的一個封裝,Python 就自帶有 socket 模塊,所以使用起來很方便。
import socket sk = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) # 監聽本地 8888 端口 host = "127.0.0.1" port = 8888 sk.bind((host, port)) sk.listen(5) while True: try: clientSk, addr = sk.accept() print("address is: %s" % str(addr)) req = clientSk.recv(1024) clientSk.sendall("...") clientSk.close() except Exception as err: print(err) clientSk.close()
這是一個極簡的 socket-server,需要注意的是,我們僅實現了 TCP協議 的部分。
解析HTTP請求拿到瀏覽器的請求很簡單,clientSk.recv() 即可獲取請求報文,而些數據我們無法直接拿來用,因為它是基于 HTTP協議 封裝的數據,在我們進行下一步操作前,需要對請求報文“解封”。而在此之前,我們需要了解請求報文的格式。最快捷的方式呢,是打開瀏覽器(以 chrome 為例),隨便打開百度啥的,F12 打開開發者工具,在 Network 一欄就可以觀察到。大概長下面這樣:
GET / HTTP/1.1 Host: xxx Connection: xxx Cache-Control: xxx Upgrade-Insecure-Requests: xxx User-Agent: xxx Accept: xxx Accept-Encoding: xxx Accept-Language: xxx Cookie: xxx
我們把關注點放在第一行,GET 方法,請求的資源路徑為 /,使用的協議是 HTTP1.1,之后就是一回車換行符 。所以我們對報文的解析如下(存在許多不足之處):
# 第一步先對數據進行解碼 decode(), # 再以行為單位進行分割 requestList = clientSk.recv(1024).decode().split(" ") # 調用寫好的函數對其進行解析 parseReq(requestList) # 解析請求報文 def parseReq(reqList): # 保存解析結果 parseRet = {} # 請求的方法,如 GET method = reqList[0].split(" ")[0] # 請求的資源路徑,如 "/" sourcePath = reqList[0].split(" ")[1] parseRet["method"] = method parseRet["sourcePath"] = sourcePath i = len(reqList) - 1 # 以 key: value 的形式保存解析結果 while i: if len(reqList[i].split(":")) == 1: i = i - 1 continue idx = reqList[i].find(":") key, value = reqList[i][0:idx], reqList[i][idx+1:] parseRet[key] = value.strip() i = i - 1 return parseRet構造響應報文
拿到了請求報文并將其解析后,我們可以開始構造響應報文的內容了,以請求靜態資源為例,假設請求報文第一行為 GET /index.html HTTP/1.1。那么我首先要做的就是先獲取路徑為 /index.html 的文件內容:
# 獲取資源內容 try: f = open(path, "r") while True: chunk = f.read(1024) if not chunk: f.close() break; content += chunk except: pass
那接下來就是構造響應報文了,同理可以觀察 HTTP 響應報文的格式,在此就不舉例了,直接上代碼:
try: f = open(path, "r") while True: chunk = f.read(1024) if not chunk: f.close() break; content += chunk except: pass # 省略了大部分頭部信息 headers = "HTTP/1.1 200 OK " contentType = "Content-Type: text/html; charset=utf-8 " contentLen = "Content-Length: " + str(len(content)) + " " # 組合成響應報文 res res = headers + contentType + contentLen + " " + content # 編碼后發送給瀏覽器, # 至此,本次通信結束 clientSk.sendall(res.encode(encoding="UTF-8")) clientSk.close()示例
到項目GitHub:https://github.com/hanrenguang/simple-webserver,下載本項目到本地,雙擊 server.py,并訪問 http://localhost:8888/index.html,你應該會看到十分親切的 Hello world!。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/38625.html
摘要:近日,推出了一個新的開源框架,該項目是一個用于創建基于微服務的應用程序的庫集合。下圖說明了和所屬的微服務框架類別。啟用后,會將其跟蹤事件發送到。 近日,Oracle推出了一個新的開源框架Helidon,該項目是一個用于創建基于微服務的應用程序的Java庫集合。和Payara Micro、Thorntail(之前的WildFly Swarm)、OpenLiberty、TomEE等項目一樣...
摘要:零前期準備版本版本核心依賴包支持包簡介是官方出品的微服務框架,底層基于驅動,大致的使用套路和相差不是很多筆者只是淺淺的了解過,可能存在理解不透的情況。一配置中的配置類有兩種,一種是用于讀取配置文件的,另一種是用于配置服務器對象的。 零 前期準備 0 版本 JDK 版本 : OpenJDK 11.0.1 IDE : idea 2018.3 Helidon Webserver : heli...
摘要:配置代理,解決跨域問題簡單的解決跨域問題,有實時重新加載功能,適用于偶爾改個文件,或者活動頁上面有簡單的前后端交互初始化全局安裝本地下載包下載包新建文件實時重新加載啟動時默認瀏覽器打開的文件代理的域名因為升級到了,所以使 gulp配置代理,解決跨域問題 簡單的解決跨域問題,有實時重新加載功能,適用于偶爾改個文件,或者H5活動頁上面有簡單的前后端交互 npm init初始化 全局安裝gu...
摘要:但是頻繁的關閉服務與重啟服務,這樣就造成了很多時間浪費,所以我們需要利用來監視文件的改動,并將這些改動重新發布到生產目錄,并重啟服務非手動。三預處理器文件編譯暫時沒用到,后面用到再增加,可以參考其他人的 關于gulp,grunt,webpack,剛走前端模塊化的我,真的是傻傻分不清楚,幸好有大神各種答疑解惑,使我略知一二,你也想知道的,也許還想知道點啥,資源羅列:1、中文官方文檔;2、...
閱讀 2314·2021-11-08 13:13
閱讀 1245·2021-10-09 09:41
閱讀 1683·2021-09-02 15:40
閱讀 3186·2021-08-17 10:13
閱讀 2546·2019-08-29 16:33
閱讀 3122·2019-08-29 13:17
閱讀 3131·2019-08-29 11:00
閱讀 3295·2019-08-26 13:40