WEB伺服器之HTTP協議

宵雲wangluo發表於2019-01-16
本篇主要為為了實現WEB伺服器,其中包含了HTTP協議的理解,以及TCP的三次握手、四次揮手等方面相關知識,同時還包含了關於web瀏覽器與伺服器之間的通訊過程。
一、web瀏覽器
通常在我們上網時會在瀏覽器的位址列輸入網址,
①、瀏覽器首先要對URL進行解析,
②、隨後透過HTTP協議定義訊息內容和步驟,即規定傳送請求的格式;
③、根據伺服器的域名透過作業系統下的解析器(DNS客戶端)向最近的DNS伺服器傳送請求獲取目標伺服器的IP地址並儲存在指定的記憶體空間內,,透過作業系統下的協議棧以及socket庫將訊息傳送出去,
④、當伺服器接收到請求訊息會返回響應訊息(該響應訊息也是根據HTTP協議定義訊息內容的格式)最後經過類似的過程返回給web瀏覽器。
接下來我們根據這幾個步驟進行解析:
1.瀏覽器怎麼對URL進行解析?
通常常用的訪問資料的機制有以下幾種:
HTTP協議:即 Hypertxt Transfer Protocal 超文字傳送協議)訪問Web伺服器,例如:
FTP協議:File Transfer Protocol,檔案傳輸協議,主要用於檔案的上傳和下載,例如:ftp://ftp.glasscom.com/dir/file1.html
File協議:本地檔案傳輸協議,例如:file://localhost/c:path/file1.zip。
maito協議:該協議可以建立一個指向電子郵件地址的超級連結,透過該連結可以在Internet中傳送電子郵件。例如:maito.tone@glasscom.com等等
2、根據HTTP協議生成怎樣格式的請求訊息和接收的響應訊息?
需要我們需要知道的是:
HTTP協議:
我們知道服務端和客戶端之間進行通訊過程便是:首先客戶端根據HTTP協議給服務端傳送請求訊息,隨後伺服器給客戶端傳送響應訊息。那麼請求訊息和響應訊息具體是什麼樣的呢?
請求訊息:
1 以下便是瀏覽器給伺服器傳送的請求訊息
2 GET / HTTP/1.1
3 Host:
4 Connection: keep-alive
5 Cache-Control: max-age=0
6 Upgrade-Insecure-Requests: 1
7 User-Agent: Mozilla/5.0 (Windows NT 10.0;Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99Safari/537.36
8Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/﹡;q=0.8
9 Accept-Encoding: gzip, deflate, br
10 Accept-Language: zh-CN,zh;q=0.9
接下來對這些資訊進行解析:
第一部分:請求頭行,包含請求型別、URI、HTTP協議版本;
請求資訊型別通常有:get、post、put等等;
第二部分:即緊跟第一行之後的,請求頭部,包含伺服器所使用的說明資訊;接下來解釋一下這些說明資訊的意思:
1、host:請求web伺服器的域名地址;
2、Connection: 表示是否持久連線;即keep-alive表示持久連線;
3、Cache-Control:指定請求和響應的快取機制;no-cache(不能快取)、no-store(在請求訊息中傳送將使得請求和響應訊息都不使用快取)、max-age(客戶機可以接收生存期不大於指定時間(以秒為單位)的響應)、max-stale(客戶機可以接收超出超時期間的響應訊息)、min-fresh(客戶機可以接收響應時間小於當前時間加上指定時間的響應)、only-if-cached等等;
4、User-Agent: HTTP協議執行的瀏覽器型別的詳細資訊;比如:谷歌/67.0.3396.99
5、Accept: 指瀏覽器可以接收的內容型別;
6、Accept-Encoding: 客戶端瀏覽器可以支援的web伺服器返回內容壓縮編碼型別;
7、Accept-Language:瀏覽器支援的語言型別,
8、Cookie: 某些網站為了辨別使用者身份、進行 session 跟蹤而儲存在使用者本地終端上的資料(通常經過加密);例如當我們上網時,某些網站能準確的推送我們想要的資訊。
第三部分:" " --> 分割header和body部分的分界線
響應訊息:
1 HTTP/1.1 200 OK
2 Bdpagetype: 1
3 Bdqid: 0x8bda58760001baca
4 Cache-Control: private
5 Connection: Keep-Alive
6 Content-Encoding: gzip
7 Content-Type: text/html
8 Cxy_all:baidu+10412ee70bbb9e9eec33f3dbcb3e2df7
9 Date: Wed, 18 Jul 2018 03:26:13GMT
10 Expires: Wed, 18 Jul 2018 03:25:42 GMT
11 Server: BWS/1.1
12 Set-Cookie: BDSVRTM=0; path=/
13 Set-Cookie: BD_HOME=0; path=/
14 Set-Cookie: H_PS_PSSID=1435_21118_20929; path=/; domain=.baidu.com
15 Strict-Transport-Security: max-age=172800
16 Vary:Accept-Encoding
17 X-Ua-Compatible: IE=Edge,chrome=1
18 Transfer-Encoding: chunked
響應訊息的解析:
第一部分:響應頭,包含:HTTP協議版本、狀態碼(1XX-告知請求處理進度和情況,2XX-成功,3XX-表示需要進一步操作,4XX-客戶端錯誤;5XX-伺服器錯誤;)
第二部分:響應頭部,包含伺服器傳送的附加資訊;這裡針對幾個重要的進行解析說明:https://www.cnblogs.com/mylanguage/p/5689879.html-->有詳細說明。
第三部分:" " --分割header和body的分割線
第四部分:包含伺服器向客戶端傳送的資料。
以上就請求訊息和響應訊息的內容格式,由瀏覽器或者客戶端將資訊根據HTTP協議轉換而來。
3、怎麼根據域名獲取伺服器的IP地址?
首先web瀏覽器會呼叫作業系統下的解析器即DNS客戶端,隨後由解析器傳送請求給最近的DNS伺服器(傳送過程與C/S架構模型一樣),若所需域名不在最近的DNS伺服器,則由該伺服器向域的DNS伺服器傳送詢查訊息,若該域名不在根域DNS伺服器上,則讓最近DNS伺服器向其下級域傳送詢查訊息,以此遞迴便能查詢到該域名所在域的DNS伺服器,最後由請求的DNS伺服器傳送響應訊息到最近的DNS伺服器,得到該域名的IP地址;
同時DNS伺服器有一個快取功能,可以記住之前查詢過的域名,如果所查詢的域名和相關資訊已經在快取中,那麼久可以直接返回響應。
二、TCP的三次握手和四次揮手
首先我們需要知道在客戶端與伺服器基於TCP協議建立聯絡時需要經過三次握手,而在斷開連線時需經歷四次揮手的過程,那麼我們來看一下該過程是怎樣的?
三次握手:
解析:
首先伺服器通常是處於監聽的狀態,而客戶端通常是主動建立連線的一方,即
1、TCP伺服器程式先建立傳輸控制塊TCB,時刻準備接受客戶程式的連線請求,此時伺服器就進入了LISTEN(監聽)狀態;
2、TCP客戶程式也是先建立傳輸控制塊TCB,然後向伺服器發出連線請求報文,這是報文首部中的同部位SYN=1,同時選擇一個初始序列號 seq=x ,此時,TCP客戶端程式進入了 SYN-SENT(同步已傳送狀態)狀態。TCP規定,SYN報文段(SYN=1的報文段)不能攜帶資料,但需要消耗掉一個序號。
3、TCP伺服器收到請求報文後,如果同意連線,則發出確認報文。確認報文中應該 ACK=1,SYN=1,確認號是ack=x+1,同時也要為自己初始化一個序列號 seq=y,此時,TCP伺服器程式進入了SYN-RCVD(同步收到)狀態。這個報文也不能攜帶資料,但是同樣要消耗一個序號。
4、TCP客戶程式收到確認後,還要向伺服器給出確認。確認報文的ACK=1,ack=y+1,自己的序列號seq=x+1,此時,TCP連線建立,客戶端進入ESTABLISHED(已建立連線)狀態。TCP規定,ACK報文段可以攜帶資料,但是如果不攜帶資料則不消耗序號。
5、當伺服器收到客戶端的確認後也進入ESTABLISHED狀態,此後雙方就可以開始通訊了。
四次揮手:
同時我們需要知道的是:通常伺服器不會主動斷開連線,而是客戶端主動斷開連線。
1、客戶端程式發出連線釋放報文,並且停止傳送資料。釋放資料包文首部,FIN=1,其序列號為seq=u(等於前面已經傳送過來的資料的最後一個位元組的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即使不攜帶資料,也要消耗一個序號。
2、伺服器收到連線釋放報文,發出確認報文,ACK=1,ack=u+1,並且帶上自己的序列號seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。TCP伺服器通知高層的應用程式,客戶端向伺服器的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有資料要傳送了,但是伺服器若傳送資料,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。
3、客戶端收到伺服器的確認請求後,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待伺服器傳送連線釋放報文(在這之前還需要接受伺服器傳送的最後的資料)。
4、伺服器將最後的資料傳送完畢後,就向客戶端傳送連線釋放報文,FIN=1,ack=u+1,由於在半關閉狀態,伺服器很可能又傳送了一些資料,假定此時的序列號為seq=w,此時,伺服器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。
5、客戶端收到伺服器的連線釋放報文後,必須發出確認,ACK=1,ack=w+1,而自己的序列號是seq=u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。注意此時TCP連線還沒有釋放,必須經過2
6、伺服器只要收到了客戶端發出的確認,立即進入CLOSED狀態。同樣,撤銷TCB後,就結束了這次的TCP連線。可以看到,伺服器結束TCP連線的時間要比客戶端早一些。
三、實現web靜態伺服器
直接看示例:
import socket
import re
def server_client(server_client_socket):
"""接收來自瀏覽器的資料和傳送報文""" # 對接收到的請求訊息進行解析request = server_client_socket.recv(1024).decode("utf-8")# 請求訊息頭部格式大概為 : GET /index.html HTTP/1.1 request_lines = request.splitlines() # 將接收到的資訊按行分割,並返回列表ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])# 若正規表示式匹配成功有返回值,則檢測是由為 "/"或者空字元,則設定預設檔案為/index.html檔案if ret:filename = ret.group(1)if filename == "/" or filename == "": filename = "/index.html"# print(request)respone = "HTTP/1.1 200 OK"respone += ""# respone += "<h2>hello world</h2>" # 檢測伺服器中是否有該檔案,有則發生內容,無則返回錯誤 try: f = open("html"+ filename, "rb")except: respone = "HTTP/1.1 404 Not found file"respone += ""respone += "<h1>Not found File</h1>"respone = respone.encode("utf-8")else: file_content = f.read() f.close() respone = respone.encode("utf-8") + file_content # 位元組之間的拼接server_client_socket.send(respone)server_client_socket.close()def main():# 1、建立套接字物件server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2、繫結本地資訊server_socket.bind(("", 6969))# 3、監聽server_socket.listen(128)while True:# 4、等待客戶端連線server_client_socket, client_addr = server_socket.accept()# 5、服務客戶端server_client(server_client_socket) server_socket.close()if __name__ == "__main__": main()
宵雲網路   伺服器 雲主機 掛機寶 VPS  網站搭建   


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31554777/viewspace-2563708/,如需轉載,請註明出處,否則將追究法律責任。

相關文章