因爲網絡間通信是基於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