首頁 > 軟體

Python網路程式設計之HTTP協定的python應用

2022-11-11 14:00:53

搭建python自帶靜態web伺服器

1. 靜態Web伺服器是什麼?

可以為發出請求的瀏覽器提供靜態檔案的程式

平時我們瀏覽百度新聞資料的時候,每天的新聞資料都會發生變化,那存取的這個頁面就是動態的,而我們開發的是靜態的,頁面的資料不會發生變化

2. 如何搭建Python自帶的靜態Web伺服器

搭建Python自帶的靜態Web伺服器使用 python3 -m http.server 埠號, 效果圖如下:

-m選項說明:

-m表示執行包裡面的模組,執行這個命令的時候,需要進入你自己指定靜態檔案的目錄,然後通過瀏覽器就能存取對應的 html檔案了,這樣一個靜態的web伺服器就搭建好了。

3. 存取搭建的靜態Web伺服器

通過瀏覽器存取搭建的靜態Web伺服器,效果圖如下:

4. 檢視瀏覽器和搭建的靜態Web伺服器的通訊過程

檢視http的通訊過程,效果圖如下:

靜態web伺服器-返回固定頁面資料

1. 開發自己的靜態Web伺服器

實現步驟:

  • 編寫一個TCP伺服器端程式
  • 獲取瀏覽器傳送的http請求報文資料
  • 讀取固定頁面資料,把頁面資料組裝成HTTP響應報文資料傳送給瀏覽器。
  • HTTP響應報文資料傳送完成以後,關閉服務於使用者端的通訊端。

2. 靜態Web伺服器-返回固定頁面資料的範例程式碼

import socket
 
 
if __name__ == '__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(("", 9000))
    # 設定監聽
    tcp_server_socket.listen(128)
    while True:
        # 等待接受使用者端的連線請求
        new_socket, ip_port = tcp_server_socket.accept()
        # 程式碼執行到此,說明連線建立成功
        recv_client_data = new_socket.recv(4096)
        # 對二進位制資料進行解碼
        recv_client_content = recv_client_data.decode("utf-8")
        print(recv_client_content)
 
        with open("static/index.html", "rb") as file:
            # 讀取檔案資料
            file_data = file.read()
        # 響應行
        response_line = "HTTP/1.1 200 OKrn"
        # 響應頭
        response_header = "Server: PWS1.0rn"
 
        # 響應體
        response_body = file_data
 
        # 拼接響應報文
        response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
        # 傳送資料
        new_socket.send(response_data)
 
        # 關閉服務與使用者端的通訊端
        new_socket.close()

靜態web伺服器-返回指定頁面資料

1. 靜態Web伺服器的問題

目前的Web伺服器,不管使用者存取什麼頁面,返回的都是固定頁面的資料,接下來需要根據使用者的請求返回指定頁面的資料

返回指定頁面資料的實現步驟:

  • 獲取使用者請求資源的路徑
  • 根據請求資源的路徑,讀取指定檔案的資料
  • 組裝指定檔案資料的響應報文,傳送給瀏覽器
  • 判斷請求的檔案在伺服器端不存在,組裝404狀態的響應報文,傳送給瀏覽器

 2. 靜態Web伺服器-返回指定頁面資料的範例程式碼

import socket
 
 
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(("", 9000))
    # 設定監聽
    tcp_server_socket.listen(128)
    while True:
        # 等待接受使用者端的連線請求
        new_socket, ip_port = tcp_server_socket.accept()
        # 程式碼執行到此,說明連線建立成功
        recv_client_data = new_socket.recv(4096)
        if len(recv_client_data) == 0:
            print("關閉瀏覽器了")
            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:
            # 動態開啟指定檔案
            with open("static" + request_path, "rb") as file:
                # 讀取檔案資料
                file_data = file.read()
        except Exception as e:
            # 請求資源不存在,返回404資料
            # 響應行
            response_line = "HTTP/1.1 404 Not Foundrn"
            # 響應頭
            response_header = "Server: PWS1.0rn"
            with open("static/error.html", "rb") as file:
                file_data = file.read()
            # 響應體
            response_body = file_data
 
            # 拼接響應報文
            response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
            # 傳送資料
            new_socket.send(response_data)
        else:
            # 響應行
            response_line = "HTTP/1.1 200 OKrn"
            # 響應頭
            response_header = "Server: PWS1.0rn"
 
            # 響應體
            response_body = file_data
 
            # 拼接響應報文
            response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
            # 傳送資料
            new_socket.send(response_data)
        finally:
            # 關閉服務與使用者端的通訊端
            new_socket.close()
 
if __name__ == '__main__':
    main()

靜態web伺服器-多工實現

1. 靜態Web伺服器的問題

目前的Web伺服器,不能支援多使用者同時存取,只能一個一個的處理使用者端的請求,那麼如何開發多工版的web伺服器同時處理 多個使用者端的請求?

可以使用多執行緒,比程序更加節省記憶體資源。

多工版web伺服器程式的實現步驟:

  • 當用戶端和伺服器端建立連線成功,建立子執行緒,使用子執行緒專門處理使用者端的請求,防止主執行緒阻塞。

  • 把建立的子執行緒設定成為守護主執行緒,防止主執行緒無法退出。

把建立的子執行緒設定成為守護主執行緒,防止主執行緒無法退出。

2. 靜態Web伺服器-多工版的範例程式碼

import socket
import threading
# 處理使用者端的請求
def handle_client_request(new_socket):
    # 程式碼執行到此,說明連線建立成功
    recv_client_data = new_socket.recv(4096)
    if len(recv_client_data) == 0:
        print("關閉瀏覽器了")
        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:
        # 動態開啟指定檔案
        with open("static" + request_path, "rb") as file:
            # 讀取檔案資料
            file_data = file.read()
    except Exception as e:
        # 請求資源不存在,返回404資料
        # 響應行
        response_line = "HTTP/1.1 404 Not Foundrn"
        # 響應頭
        response_header = "Server: PWS1.0rn"
        with open("static/error.html", "rb") as file:
            file_data = file.read()
        # 響應體
        response_body = file_data
 
        # 拼接響應報文
        response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
        # 傳送資料
        new_socket.send(response_data)
    else:
        # 響應行
        response_line = "HTTP/1.1 200 OKrn"
        # 響應頭
        response_header = "Server: PWS1.0rn"
 
        # 響應體
        response_body = file_data
 
        # 拼接響應報文
        response_data = (response_line + response_header + "rn").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(("", 9000))
    # 設定監聽
    tcp_server_socket.listen(128)
 
    while True:
        # 等待接受使用者端的連線請求
        new_socket, ip_port = tcp_server_socket.accept()
        print(ip_port)
        # 當用戶端和伺服器建立連執行緒,建立子執行緒
        sub_thread = threading.Thread(target=handle_client_request, args=(new_socket,))
        # 設定守護主執行緒
        sub_thread.setDaemon(True)
        # 啟動子執行緒執行對應的任務
        sub_thread.start()
 
 
if __name__ == '__main__':
    main()

靜態web伺服器-物件導向開發

1. 以物件導向的方式開發靜態Web伺服器

實現步驟:

  • 把提供服務的Web伺服器抽象成一個類(HTTPWebServer)
  • 提供Web伺服器的初始化方法,在初始化方法裡面建立socket物件
  • 提供一個開啟Web伺服器的方法,讓Web伺服器處理使用者端請求操作。

2. 靜態Web伺服器-物件導向開發的範例程式碼

import socket
import threading
# 定義web伺服器類
class HttpWebServer(object):
    def __init__(self):
        # 建立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(("", 9000))
        # 設定監聽
        tcp_server_socket.listen(128)
        # 儲存建立成功的伺服器通訊端
        self.tcp_server_socket = tcp_server_socket
 
    # 處理使用者端的請求
    @staticmethod
    def handle_client_request(new_socket):
        # 程式碼執行到此,說明連線建立成功
        recv_client_data = new_socket.recv(4096)
        if len(recv_client_data) == 0:
            print("關閉瀏覽器了")
            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:
            # 動態開啟指定檔案
            with open("static" + request_path, "rb") as file:
                # 讀取檔案資料
                file_data = file.read()
        except Exception as e:
            # 請求資源不存在,返回404資料
            # 響應行
            response_line = "HTTP/1.1 404 Not Foundrn"
            # 響應頭
            response_header = "Server: PWS1.0rn"
            with open("static/error.html", "rb") as file:
                file_data = file.read()
            # 響應體
            response_body = file_data
 
            # 拼接響應報文
            response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
            # 傳送資料
            new_socket.send(response_data)
        else:
            # 響應行
            response_line = "HTTP/1.1 200 OKrn"
            # 響應頭
            response_header = "Server: PWS1.0rn"
 
            # 響應體
            response_body = file_data
 
            # 拼接響應報文
            response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
            # 傳送資料
            new_socket.send(response_data)
        finally:
            # 關閉服務與使用者端的通訊端
            new_socket.close()
 
    # 啟動web伺服器進行工作
    def start(self):
        while True:
            # 等待接受使用者端的連線請求
            new_socket, ip_port = self.tcp_server_socket.accept()
            # 當用戶端和伺服器建立連執行緒,建立子執行緒
            sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,))
            # 設定守護主執行緒
            sub_thread.setDaemon(True)
            # 啟動子執行緒執行對應的任務
            sub_thread.start()
# 程式入口函數
def main():
    # 建立web伺服器物件
    web_server = HttpWebServer()
    # 啟動web伺服器進行工作
    web_server.start()
if __name__ == '__main__':
    main()

靜態web伺服器-命令列啟動動態繫結埠號

1. 開發命令列啟動動態繫結埠號的靜態web伺服器

實現步驟:

  • 獲取執行python程式的終端命令列引數
  • 判斷引數的型別,設定埠號必須是整型
  • 給Web伺服器類的初始化方法新增一個埠號引數,用於繫結埠號

2. 靜態Web伺服器-命令列啟動動態繫結埠號的範例程式碼

import socket
import threading
import sys
# 定義web伺服器類
class HttpWebServer(object):
    def __init__(self, port):
        # 建立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(("", port))
        # 設定監聽
        tcp_server_socket.listen(128)
        # 儲存建立成功的伺服器通訊端
        self.tcp_server_socket = tcp_server_socket
 
    # 處理使用者端的請求
    @staticmethod
    def handle_client_request(new_socket):
        # 程式碼執行到此,說明連線建立成功
        recv_client_data = new_socket.recv(4096)
        if len(recv_client_data) == 0:
            print("關閉瀏覽器了")
            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:
            # 動態開啟指定檔案
            with open("static" + request_path, "rb") as file:
                # 讀取檔案資料
                file_data = file.read()
        except Exception as e:
            # 請求資源不存在,返回404資料
            # 響應行
            response_line = "HTTP/1.1 404 Not Foundrn"
            # 響應頭
            response_header = "Server: PWS1.0rn"
            with open("static/error.html", "rb") as file:
                file_data = file.read()
            # 響應體
            response_body = file_data
 
            # 拼接響應報文
            response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
            # 傳送資料
            new_socket.send(response_data)
        else:
            # 響應行
            response_line = "HTTP/1.1 200 OKrn"
            # 響應頭
            response_header = "Server: PWS1.0rn"
 
            # 響應體
            response_body = file_data
 
            # 拼接響應報文
            response_data = (response_line + response_header + "rn").encode("utf-8") + response_body
            # 傳送資料
            new_socket.send(response_data)
        finally:
            # 關閉服務與使用者端的通訊端
            new_socket.close()
 
    # 啟動web伺服器進行工作
    def start(self):
        while True:
            # 等待接受使用者端的連線請求
            new_socket, ip_port = self.tcp_server_socket.accept()
            # 當用戶端和伺服器建立連執行緒,建立子執行緒
            sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,))
            # 設定守護主執行緒
            sub_thread.setDaemon(True)
            # 啟動子執行緒執行對應的任務
            sub_thread.start()
 
# 程式入口函數
def main():
 
    print(sys.argv)
    # 判斷命令列引數是否等於2,
    if len(sys.argv) != 2:
        print("執行命令如下: python3 xxx.py 8000")
        return
 
    # 判斷字串是否都是數位組成
    if not sys.argv[1].isdigit():
        print("執行命令如下: python3 xxx.py 8000")
        return
 
    # 獲取終端命令列引數
    port = int(sys.argv[1])
    # 建立web伺服器物件
    web_server = HttpWebServer(port)
    # 啟動web伺服器進行工作
    web_server.start()
if __name__ == '__main__':
    main()

到此這篇關於Python網路程式設計之HTTP協定的python應用的文章就介紹到這了,更多相關python http協定內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com