超文本傳輸協議,是一個基於請求與響應,無狀態的,應用層的協議,常基於TCP/IP協議傳輸數據,互聯網上應用最爲普遍的一種網絡協議,全部的WWW文件都必須遵照這個標準。設計HTTP的初衷是爲了提供一種發佈和接收HTML頁面的方法html
一個HTTP請求報文由請求行(request line)、請求頭(header)、空行和請求數據4個部分組成,下圖給出了請求報文的通常格式python
請求行由請求方法字段、URL字段和HTTP協議版本字段3個字段組成,它們用空格分隔。例如,GET/index.htmlHTTP/1.1web
請求頭部由關鍵字/值對組成,每行一對,關鍵字和值用英文冒號「:」分隔。請求頭部通知服務器有關於客戶端請求的信息,典型的請求頭有常見的請求頭屬性ajax
最後一個請求頭以後是一個空行,發送回車符和換行符,通知服務器如下再也不有請求頭。算法
HTTP狀態碼的英文爲HTTP Status Code。狀態代碼由三位數字組成,第一個數字定義了響應的類別,且有五種可能取值。瀏覽器
狀態響應頭緩存
常見的狀態碼安全
首先聲明,HTTP協議沒有對傳輸的數據大小進行限制,HTTP協議規範也沒有對URL長度進行限制。 而在實際開發中存在的限制主要有:服務器
POST的安全性要比GET的安全性高。websocket
注意:這裏所說的安全性和上面GET提到的「安全」不是同個概念。上面「安全」的含義僅僅是不做數據修改,而這裏安全的含義是真正的Security的含義,好比:經過GET提交數據,用戶名和密碼將明文出如今URL上,由於(1)登陸頁面有可能被瀏覽器緩存, (2)其餘人查看瀏覽器的歷史紀錄,那麼別人就能夠拿到你的帳號和密碼了
HTTPS是一種經過計算機網絡進行安全通訊的傳輸協議,經由HTTP進行通訊,利用SSL/TLS創建全信道,加密數據包。 HTTPS使用的主要目的是提供對網站服務器的身份認證,同時保護交換數據的隱私與完整性。 PS:TLS是傳輸層加密協議,前身是SSL協議,由網景公司1995年發佈,有時候二者不區分
客戶端本身封裝一種加密算法,將給服務端發送的數據進行加密,而且將數據加密的方式即祕鑰發送給密文,服務端收到祕鑰和數據,用祕鑰進行解密
服務器端爲客戶端統一建立一個加密方式,由服務器端指定建立,稱爲公鑰,服務器端所建立的加密方式統一的分發給即將要進行服務器鏈接的客戶端,客戶端只須要將密文發送給服務端,服務端經過公鑰加密,可是的創建兩次鏈接,先傳送公鑰,也存在隱患,模擬某些服務器的公鑰,發送的數據被第三方截取。
用到三方機構,數字證書,服務器端和客戶端足以信任的機構,服務器端將公鑰發送給三方機構,在三方機構 作一個防僞標識,數字簽名,公鑰攜帶三方機構的證書發送給客戶端,客戶端使用公鑰對數據進行加密。
客戶端輸入URL回車,DNS解析域名獲得服務器的IP地址,服務器在80端口監聽客戶端請求,端口經過TCP/IP協議(能夠經過Socket實現)創建鏈接。HTTP屬於TCP/IP模型中的運用層協議,因此通訊的過程實際上是對應數據的入棧和出棧
報文從運用層傳送到運輸層,運輸層經過TCP三次握手和服務器創建鏈接,四次揮手釋放鏈接。
WebSocket是基於HTTP協議的,或者說借用了HTTP協議來完成一部分握手
GET /chatsocket HTTP/1.1 Host: 127.0.0.1:8002 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: http://localhost:63342 Sec-WebSocket-Version: 13 # 版本 Sec-WebSocket-Key: mnwFxiOlctXFN/DeMt1Amg== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key是一個Base64 encode的值,這個是瀏覽器隨機生成的,發送給服務器
服務端從請求(HTTP的請求頭)信息中提取Sec-WebSocket-Key,利用magic_string和Sec-WebSocket-Key進行hmac1
加密,再進行base64
加密
將加密結果響應給客戶端,服務器會返回下列東西,表示已經接受到請求, 成功創建WebSocket
headers = get_headers(data) # 提取請求頭信息 # 對請求頭中的sec-websocket-key進行加密 response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \ "Upgrade:websocket\r\n" \ "Connection: Upgrade\r\n" \ "Sec-WebSocket-Accept: %s\r\n" \ "WebSocket-Location: ws://127.0.0.1:9527\r\n\r\n" value = headers['Sec-WebSocket-Key'] + magic_string print(value) ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest()) response_str = response_tpl % (ac.decode('utf-8')) # 響應【握手】信息 conn.send(response_str.encode("utf8"))
依然是固定的,經過Upgrade告訴客戶端即將升級的是WebSocket協議,而不是mozillasocket,urnarsocket** 或者shitsocket。
而後,Sec-WebSocket-Accept這個則是通過服務器確認,而且加密事後的Sec-WebSocket-Key。服務器:好啦好啦,知道啦,給你看個人ID CARD來證實行了吧。
Sec-WebSocket-Protocol則是表示最終使用的協議。
hashstr = b'\x81\x83\xceH\xb6\x85\xffz\x85' # b'\x81 \x83 \xceH\xb6\x85\xffz\x85' # 將第二個字節也就是 \x83 第9-16位 進行與127進行位運算 payload = hashstr[1] & 127 print(payload) if payload == 127: extend_payload_len = hashstr[2:10] mask = hashstr[10:14] decoded = hashstr[14:] # 當位運算結果等於127時,則第3-10個字節爲數據長度 # 第11-14字節爲mask 解密所需字符串 # 則數據爲第15字節至結尾 if payload == 126: extend_payload_len = hashstr[2:4] mask = hashstr[4:8] decoded = hashstr[8:] # 當位運算結果等於126時,則第3-4個字節爲數據長度 # 第5-8字節爲mask 解密所需字符串 # 則數據爲第9字節至結尾 if payload <= 125: extend_payload_len = None mask = hashstr[2:6] decoded = hashstr[6:] # 當位運算結果小於等於125時,則這個數字就是數據的長度 # 第3-6字節爲mask 解密所需字符串 # 則數據爲第7字節至結尾 str_byte = bytearray() for i in range(len(decoded)): byte = decoded[i] ^ mask[i % 4] str_byte.append(byte) print(str_byte.decode("utf8"))
import struct msg_bytes = "hello".encode("utf8") token = b"\x81" length = len(msg_bytes) if length < 126: token += struct.pack("B", length) elif length == 126: token += struct.pack("!BH", 126, length) else: token += struct.pack("!BQ", 127, length) msg = token + msg_bytes print(msg)
ajax輪詢的原理很是簡單,讓瀏覽器隔個幾秒就發送一次請求,詢問服務器是否有新信息
long poll 其實原理跟 ajax輪詢差很少,都是採用輪詢的方式,不過採起的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說,客戶端發起請求後,若是沒消息,就一直不返回 Response 給客戶端。直到有消息才返回,返回完以後,客戶端再次創建鏈接,周而復始。
這兩種方式都不是最好的方式,須要不少資源,一種須要更快的速度,一種須要更多的’電話。這兩種都會致使’電話’的需求愈來愈高。
忘記說了 HTTP 仍是一個無狀態協議。通俗的說就是,服務器由於天天要接待太多客戶了,是個健忘鬼,你一掛電話,他就把你的東西全忘光了,把你的東西全丟掉了。你第二次還得再告訴服務器一遍。
只須要通過一次 HTTP 請求,就能夠作到源源不斷的信息傳送了,當服務器完成協議升級後(HTTP --—> Websocket),服務端就能夠主動推送信息給客戶端啦。