web服務(wù)器基礎(chǔ)知識
http協(xié)議
瀏覽器發(fā)送給服務(wù)器的數(shù)據(jù) (這些數(shù)據(jù)是有格式的,這就是http協(xié)議)
瀏覽器-->服務(wù)器發(fā)送的請求格式如下:
# 表示請求的目標(biāo)、協(xié)議版本
GET / HTTP/1.1
# 表示服務(wù)器的IP地址和端口
Host: 127.0.0.1:8080
# 表示是長鏈接
Connection: keep-alive
# 表示谷歌瀏覽器告訴服務(wù)器,瀏覽器可以處理https協(xié)議
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, br
# 表示能接收的語言,能接收中文
Accept-Language: zh-CN,zh;q=0.9
服務(wù)器-->瀏覽器回送的數(shù)據(jù)格式如下:
HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0x9dd09c83000204a0
# 表示你的緩存是共享的、還是私有的,現(xiàn)在是私有的
Cache-Control: private
Connection: Keep-Alive
# 編碼格式,瀏覽器就按照這個格式來解壓
Content-Encoding: gzip
# 服務(wù)器傳回的內(nèi)容格式、字符集
Content-Type: text/html; charset=utf-8
Cxy_all: baidu+34491ab9ca3c8ba32cebe1d26059f593
# 表示服務(wù)器當(dāng)前的時間
Date: Sun, 23 Jun 2019 03:38:04 GMT
Expires: Sun, 23 Jun 2019 03:37:52 GMT
# 服務(wù)器:BWS是百度服務(wù)器的一個簡稱
Server: BWS/1.1
# 設(shè)置Cookie
Set-Cookie: delPer=0; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=0; path=/
Set-Cookie: H_PS_PSSID=1441_21127_29135_29237_28518_29099_29131_29369_28833_29220_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Vary: Accept-Encoding
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
<h1>hahaha</h1>
瀏覽器首先向服務(wù)器發(fā)送HTTP請求,請求包括:
方法:GET還是POST,GET僅請求資源,POST會附帶用戶數(shù)據(jù);
路徑:/full/url/path;
域名:由Host頭指定:Host: www.sina.com
以及其他相關(guān)的Header;
如果是POST,那么請求還包括一個Body,包含用戶數(shù)據(jù)
實現(xiàn)簡單的http服務(wù)器
import socket
def service_client(new_socket):
"""為這個客戶端返回數(shù)據(jù)"""
# 1. 接收瀏覽器發(fā)送過來的請求,即http請求
# GET / HTTP/1.1
# ……
request = new_socket.recv(1024)
print(request)
# 2. 返回http格式的數(shù)據(jù)給瀏覽器
# 2.1 準(zhǔn)備發(fā)送給瀏覽器的數(shù)據(jù):Header
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
# 2.2 準(zhǔn)備發(fā)送給瀏覽器的數(shù)據(jù):Body
response += "<h1>hahaha</h1>"
new_socket.send(response.encode("utf-8"))
# 關(guān)閉套接字
new_socket.close()
def main():
"""用來完成整體的控制"""
# 1. 創(chuàng)建套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2. 綁定
tcp_server_socket.bind(("", 7890))
# 3. 變?yōu)楸O(jiān)聽套接字(最大連接數(shù)是128)
tcp_server_socket.listen(128)
while True:
# 4. 等待新客戶端的鏈接
new_socket, client_addr = tcp_server_socket.accept()
# 5. 為這個客戶端服務(wù)
service_client(new_socket)
# 6.關(guān)閉監(jiān)聽套接字
tcp_server_socket.close()
if __name__ == "__main__":
main()
三次握手四次揮手
三次握手四次揮手的目的:
三次握手保證雙方都能準(zhǔn)備好資源
四次握手保證雙方的資源都能釋放掉
三次握手:
1.客戶端告訴服務(wù)器準(zhǔn)備好資源
2.是服務(wù)器告訴客服端,準(zhǔn)備好資源了
客戶端問服務(wù)端你準(zhǔn)備好了嗎?
3.客戶端告訴服務(wù)端準(zhǔn)備好了
四次揮手:
第一次揮手:客服端的頁面沒有變化,在底層會發(fā)送一個tcp的數(shù)據(jù)包給服務(wù)端
第二次揮手:服務(wù)端給客服端回復(fù),并解阻塞
第三次揮手:服務(wù)端給客服端,解阻塞調(diào)用close函數(shù)
第四次揮手:客服端給服務(wù)端的回復(fù)
#解阻塞函數(shù)
recv_data=new_socket.recv(1024)
if recv_data:#如果有數(shù)據(jù)
xxxx
else:
new_socket.close()#沒有數(shù)據(jù)時關(guān)閉
1客服端調(diào)用close為什么不會被占用?
客服端端口隨機(jī)分配
2服務(wù)端調(diào)用 close端口被占用解決方法?
函數(shù)socket.SO_REUSEADDR重復(fù)調(diào)用這個端口.'
3為什么是四次揮手不是三次?
因為第一次揮手之后服務(wù)端有兩件事要做第一件事盡快回復(fù)給客服端
第二件事解阻塞調(diào)用close函數(shù),現(xiàn)在把三次握手改成僅需要兩次握手,死鎖是可能發(fā)生的(死鎖就是常說的偽進(jìn)程)