1. 程式人生 > 實用技巧 >【Python高階程式設計037 ● 靜態web伺服器 ● 靜態Web伺服器-多工版】

【Python高階程式設計037 ● 靜態web伺服器 ● 靜態Web伺服器-多工版】


---------Python基礎程式設計---------

Author : AI菌


【內容講解】

一、需求
    1、單任務版的Web伺服器,不能支援多使用者同時訪問,只能一個一個的處理客戶端的請求。
       例如使用網路除錯助手,建立連線後,不傳送資料,主執行緒就會阻塞,其他使用者就無法建立連線,
       需要等網路除錯助手的請求處理完畢,服務端才能繼續處理後面的請求。
    2、開發多工版的web伺服器同時處理多個客戶端的請求。

二、實現步驟
    1、使用多執行緒。當客戶端和服務端建立連線成功,建立子執行緒,使用子執行緒專門處理客戶端的請求,防止主執行緒阻塞。
    
2、把建立的子執行緒設定成為守護主執行緒,防止主執行緒無法退出。

【程式碼演示】

"""
一、需求
    1、單任務版的Web伺服器,不能支援多使用者同時訪問,只能一個一個的處理客戶端的請求。
       例如使用網路除錯助手,建立連線後,不傳送資料,主執行緒就會阻塞,其他使用者就無法建立連線,
       需要等網路除錯助手的請求處理完畢,服務端才能繼續處理後面的請求。
    2、開發多工版的web伺服器同時處理多個客戶端的請求。

二、實現步驟
    1、使用多執行緒。當客戶端和服務端建立連線成功,建立子執行緒,使用子執行緒專門處理客戶端的請求,防止主執行緒阻塞。
    2、把建立的子執行緒設定成為守護主執行緒,防止主執行緒無法退出。
""" import socket import threading # 處理客戶端的請求 def handle_client_request(new_socket): # 接收客戶端的資料 recv_client_data = new_socket.recv(4096) # 判斷接收的客戶端資料是否為0 if len(recv_client_data) == 0: new_socket.close() return # 對二進位制資料進行解碼 recv_client_content = recv_client_data.decode("
utf-8") print("來自客戶端的資料:", recv_client_content) # 對資料按照空格進行分割,分割2次 request_list = recv_client_content.split(" ", maxsplit=2) # 獲取請求資源的路徑 request_path = request_list[1] print("擷取的請求資源的路徑:", request_path) # 判斷請求的是否是根目錄,如果是根目錄設定返回的資訊 if request_path == "/": request_path = "/index.html" try: # 讀取檔案資料 # rb表示以二進位制的方式讀取檔案資料,圖片資料需要以二進位制格式開啟,使用rb with open("static" + request_path, "rb") as file: file_data = file.read() except Exception as e: # 程式碼執行到此,說明沒有請求的檔案,返回404狀態資訊 # 響應行 response_line = "HTTP/1.1 404 NOT FOUND\r\n" # 響應頭 response_header = "server:DiamondDownload1.0\r\n" # 讀取404頁面資料 with open("static/error.html", "rb") as file: file_data = file.read() # 響應體 response_body = file_data # 把資料封裝成http響應報文格式的資料 response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body # 傳送給瀏覽器的響應報文資料 new_socket.send(response_data) else: # 程式碼執行到此,說明有請求的檔案,返回200狀態資訊 # 響應行 response_line = "HTTP/1.1 200 OK\r\n" # 響應頭 response_header = "server:DiamondDownload1.0\r\n" # 響應體 response_body = file_data # 把資料封裝成http響應報文格式的資料 response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body # 傳送給瀏覽器的響應報文資料 new_socket.send(response_data) finally: # 關閉服務端與客戶端套接字 new_socket.close() # 程式入口函式 def main(): # 建立tcp服務端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 設定埠號複用, 程式退出埠立即釋放 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 繫結埠號 tcp_server_socket.bind(("", 8000)) # 設定監聽 tcp_server_socket.listen(128) # 迴圈響應客戶端請求 while True: # 等待接受客戶端的連線請求 new_socket, port = tcp_server_socket.accept() # 程式碼執行到此,說明連線建立成功 # 當客戶端和伺服器建立連線程,建立子執行緒 sub_thread = threading.Thread(target=handle_client_request, args=(new_socket,)) # 設定守護執行緒 sub_thread.setDaemon(True) # 啟動子執行緒執行對應的任務 sub_thread.start() if __name__ == '__main__': main()

【執行結果】

服務端程式控制臺列印結果:

來自客戶端的資料: GET / HTTP/1.1
Host: 192.168.1.64:8000
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9


擷取的請求資源的路徑: /
來自客戶端的資料: GET /favicon.ico HTTP/1.1
Host: 192.168.1.64:8000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://192.168.1.64:8000/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

瀏覽器訪問:

【往期精彩】

▷【Python基礎程式設計196 ● 讀取檔案的4種方式】
▷【Python基礎程式設計197 ● 讀取檔案的4種方式】
▷【Python基礎程式設計198 ● 讀取檔案的4種方式】
▷【Python基礎程式設計199 ● Python怎麼讀/寫很大的檔案】
▷【Python基礎程式設計200 ● 讀取檔案的4種方式】
▷【Python基礎程式設計201 ● 讀取檔案的4種方式】
▷【Python基礎程式設計202 ● 讀取檔案的4種方式】
▷【Python基礎程式設計203 ● 讀取檔案的4種方式】

【加群交流】