長連接優點
HTTP為什么要開啟長連接呢?
主要是為了節省建立的時間,請求可以復用同一條TCP鏈路,不用重復進行三握+四揮
如果沒有長連接,每次請求都做三握+四揮
如果有長鏈接,在一個 TCP 連接中可以持續發送多份數據而不會斷開連接,即請求可以復用TCP鏈路
長連接缺點
長連接不是萬能的,存在隊頭阻塞
隊頭阻塞
如果僅僅使用一個連接,它需要發起請求、等待響應,之后才能發起下一個請求。
在請求應答過程中,如果出現任何狀況,剩下所有的工作都會被阻塞在那次請求應答之后。
這就是“隊頭阻塞”,它會阻礙網絡傳輸和Web頁面渲染,直至失去響應。
為了防止這種問題,現代瀏覽器會針對單個域名開啟6個連接,通過各個連接分別發送請求。
它實現了某種程度上的并行,但是每個連接仍會受到“隊頭阻塞”的影響
pipline
為解決隊頭阻塞,提出 pipline 方案
雖然在一個 tcp 鏈路中實現多個 http 并發,但因為該方案有缺陷,大部分瀏覽器默認關閉 pipeline
其一:是因為返回時會阻塞,誰先發送,誰先返回,順序絕對不能亂
其二:只能是請求(get、head等)才能應用 pipeline
HTTP開啟長連接
C
開啟 HTTP 長連接,對前端很簡單,方式如下:
協議 開啟 關閉
HTTP1.0 Connection: keep-alive 默認
HTTP1.1 默認 Connection: close
S
Keep-Alive 需要服務端支持:
Httpd 守護進程,如 nginx 需要設置 keepalive_timeout
keepalive_timout 時間值:一個 http 產生的 tcp 連接在傳送完最后一個響應后,還需要 hold 住 keepalive_timeout 秒后,才開始關閉連接
- keepalive_timeout=0:建立tcp連接 + 傳送http請求 + 執行時間 + 傳送http響應 + 關閉tcp連接 + 2MSL
- keepalive_timeout>0:建立tcp連接 + (最后一個響應時間 – 第一個請求時間) + 關閉tcp連接 + 2MSL
代碼
HTTP1.1 開啟 keepalive 長連接
// clients
func doGet(client *http.Client, url string, id int) {resp, err := client.Get