python實現外部靜態服務器,瀏覽器通過HTTP與之通信2

        因爲網絡間通信是基於TCP協議傳輸數據的,而服務器與瀏覽器之間通信是基於HTTP協議的,那麼下面基於python實現一個tcp服務器,瀏覽器可以基於http協議進行發送請求和解析。瀏覽器展示返回的一個標準的HTML網頁,此外實現服務器解析客戶端多次請求並且返回請求結果。即:客戶端根據HTML裏面的各種鏈接,再發送HTTP請求給服務器,拿到相應的圖片、視頻、Flash、JavaScript腳本、CSS等各種資源,最終顯示出一個完整的頁面。

1.代碼實現web服務器,實現解析用戶請求並且返回對應結果

#coding=utf-8
import socket
import re

def handle_client(client_socket):
    "爲一個客戶端進行服務"
    recv_data = client_socket.recv(1024).decode('gbk', errors="ignore") #報錯忽略
    '''
    注意儘管客戶端可以根據返回的HTML裏的鏈接發送二次請求,但是要想正確返回請求內容,需要服務器能夠解析
    這些請求內容,找到這些內容讀取後send給客戶端。所以下面要做的就是解析客戶端的請求如下格式:
    b'GET /images/qt-logo.png HTTP/1.1\r\nHost: 127.0.0.1:7890\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36\r\nAccept: image/webp,image/apng,image/*,*/*;q=0.8\r\nReferer: http://127.0.0.1:7890/\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n\r\n'
    '''
    request_header_lines = recv_data.splitlines() #1.將服務器接收的數據按HTTP格式進行切分,模式分割符就是\r\n
    for line in request_header_lines:   #打印是爲了測試使用
        print(line)

    http_request_line = request_header_lines[0]  #2.獲取請求數據的第一行,比如:GET /images/qt-logo.png HTTP/1.1
    get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)  #3.獲取客戶端請求的文件名images/qt-logo.png
    print("file name is ===>%s" % get_file_name)  # for test

    # 如果沒有指定訪問哪個頁面。例如index.html
    # GET / HTTP/1.1
    if get_file_name == "/":
        get_file_name = DOCUMENTS_ROOT + "/index.html"
    else:
        get_file_name = DOCUMENTS_ROOT + get_file_name

    print("file name is ===2>%s" % get_file_name) #for test

    try:
        f = open(get_file_name, "rb")
    except IOError: #如果沒有該文件,則返回404 not found
        # 404表示沒有這個頁面
        response_headers = "HTTP/1.1 404 not found\r\n"
        response_headers += "\r\n"
        response_body = "====sorry ,file not found===="
    else:  #注意這裏else的使用,找到了該文件返回200 OK
        response_headers = "HTTP/1.1 200 OK\r\n"
        response_headers += "\r\n"
        response_body = f.read() #讀取用戶請求的文件,注意這裏如果文件很大,可以循環讀取
        f.close()

    finally:# 在這裏將讀取的文件發送給客戶端。
        # 因爲頭信息在組織的時候,是按照字符串組織的,不能與以二進制打開文件讀取的數據合併,因此分開發送
        # 先發送response的頭信息
        client_socket.send(response_headers.encode('gbk')) #注意如果在linux上測試的話,改成utf-8
        # 再發送body
        client_socket.send(response_body)
        client_socket.close()

def main():
    "作爲程序的主控制入口"
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 設置當服務器先close 即服務器端4次揮手之後資源能夠立即釋放,這樣就保證了,下次運行程序時 可以立即綁定7788端口
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind(("", 7788))
    server_socket.listen(128)
    while True:
        client_socket, clien_cAddr = server_socket.accept()
        handle_client(client_socket)


#這裏配置服務器
DOCUMENTS_ROOT = "./html"  #因爲文件都放在當前路徑下的html文件夾裏,所以這裏定義一個固定路徑,存放的是提前寫好的網頁文件。

if __name__ == "__main__":
    main()

2.測試展示與分析

       啓動上面程序,打開web瀏覽器,訪問該服務器。注意,之前我們服務器是固定返回一個頁面給瀏覽器,不去對請求的數據進行解析處理,所以192.168.1.1:7788後面跟任何字符串都行,都不會報錯,現在則不行,服務器會對瀏覽器的請求進行解析,如下因爲找不到/aaaa/bbbb/ccc而報錯,404 NOT FOUND

2.1錯誤訪問地址

  2.2.正常向服務器發送請求

     所以這個時候我們就需要按服務器上的正常部署是文件去訪問了.比如我們在服務器上配置默認的路徑就是index.html,所以我們直接用瀏覽器訪問http://192.168.1.1:7788/index.html 或者http://192.168.1.1:7788結果都是一樣,如下,注意下面網頁的圖片已經加載正常了。實現了客戶端根據HTML裏面的各種鏈接,再發送HTTP請求給服務器,拿到相應的圖片、視頻、Flash、JavaScript腳本、CSS等各種資源,最終顯示出一個完整的頁面

2.3服務器內部打印的瀏覽器請求與解析後的結果如下: 

  可以看出雖然請求了一次,但是瀏覽器因爲網頁內嵌的url,隨後發送了多次請求,並且都得到了正確響應。

GET / HTTP/1.1
Host: 192.168.1.1:7788
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

file name is ===>/
file name is ===2>./html/index.html
GET /classic.css HTTP/1.1
Host: 192.168.1.1:7788
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36
Accept: text/css,*/*;q=0.1
Referer: http://192.168.1.1:7788/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

file name is ===>/classic.css
file name is ===2>./html/classic.css
GET /images/qt-logo.png HTTP/1.1
Host: 192.168.1.1:7788
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://192.168.1.1:7788/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

file name is ===>/images/qt-logo.png
file name is ===2>./html/images/qt-logo.png
GET /images/trolltech-logo.png HTTP/1.1
Host: 192.168.1.1:7788
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://192.168.1.1:7788/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

file name is ===>/images/trolltech-logo.png
file name is ===2>./html/images/trolltech-logo.png

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章