add by zhj: 客戶端使用的是Apache的HttpClient
原文:https://blog.csdn.net/Kingson_Wu/article/details/80102077
作者:Torreson
最近心里有幾個疑問想要解決:
1. keepalive 是否開啟服務端控制還是客戶端控制?
2. keepalive的時間是由服務端控制還是客戶端控制?
3. keepalive時間一到,是由客戶端主動關閉還是服務端主動關閉?
4. 如果客戶端不是httpclient,使用telnet連接服務端?
下面帶着上述問題,模擬相關場景進行抓包實驗,先展示一張圖,便於后續的分析:
場景一
1. httpclient連續兩次請求,間隔10秒,服務端設置keealive時間為5秒
2. client代碼:
closeableHttpClient.execute(httpGet); Thread.sleep(10000); closeableHttpClient.execute(httpGet); Thread.sleep(10000);
3. 服務端設置keepalive:
((AbstractProtocol) connector.getProtocolHandler())
.setKeepAliveTimeout(5000);
4. 使用wireshark抓包
從圖中可以看到:第一次請求的端口是64360,並且在5秒之后,由服務端主動發送fin包關閉連接。而第二次請求顯然已經不能復用連接了,使用的新的端口64361重新連接服務器,后續的行為基本和第一次請求一樣。
5. 查看本地的端口狀態
可以看到服務端8080端口進入了FIN_WAIT_2狀態,參照文中剛開始的第一張圖,這顯然是主動關閉方才會有的狀態,同樣64360進入了CLOSE_WAIT狀態,說明client端是被動關閉的。
這里比較奇怪的是,沒能看到服務端進入TIME_WAIT狀態(可能是環境問題,即使是客戶端主動關閉也沒看到)。
場景二
1. 改造場景一,httpclient請求頭加上Connection: Close
,請求時間間隔改為1秒 –
httpGet.addHeader("Connection", "Close");
2. wireshark抓包
可以看到,主動關閉方還是服務器端,並且立刻關閉,並沒有等待keepalive時間到達。
場景三
1. httpclient默認keealive,服務端響應頭加上Connection: Close
response.setHeader("Connection", "Close");
2. wireshark抓包
從圖中看出,主動關閉方是客戶端。如果客戶端不是httpclient,是telnet,客戶端會主動關閉?后面實驗一下。
如果客戶端和服務端都加上Connection: Close
,那么主動關閉方是客戶端(已經抓包查看過)
場景四
1. 跟場景四一樣,client有httpclient改成telnet,服務端返回Connection: Close
以及keepalive時間為 5秒
2. telnet客戶端
3. wireshark抓包
從圖中可以看出,雖然服務端返回Connection: Close
,但是telnet客戶端並不理會,而是等到服務端keepalive時間到了(5秒),才由服務端關閉。
服務端keepalive改成30秒,同樣是30秒后由服務端主動關閉。
場景五
1. HttpClient客戶端keepalive=3秒,服務端keepalive=5秒
2. wireshark 抓包
服務端5秒后主動關閉,而不是期望的客戶端主動關閉。估計客戶端主動關閉只有在瀏覽器端才能實現,或者需要合適的參數和客戶端實現。
答疑
基於文中開頭的疑問做一個解答
1. keepalive 是否開啟服務端控制還是客戶端控制?
keepalive可以由雙方共同控制,需要雙方都開啟才能生效,HTTP1.1客戶端默認開啟,客戶端想關閉可以通過設置Connection: Close,服務端同樣想關閉可以設置Connection: Close。雙方哪方先收到Connection: Close 則由收到方關閉(前提是雙方的實現都支持,比如telnet就不支持)
2. keepalive的timeout時間是由服務端決定還是客戶端決定?
add by zhj: 案例中用的Apache的HttpClient,它應該是沒有定時任務去關閉keepalive超時的連接,應該是當你用它再次請求時,它才會去檢查keepalive是否過期,如果過期,才關閉,並創建新的連接。
但一般的Http連接池都會實現定時檢查連接的可用性,其實一項就是keepalive,如果過期,那就關閉。比如OkHttp就使用了Http連接池。
3. keepalive時間一到,是由客戶端主動關閉還是服務端主動關閉?
根據上述的分析,哪方的時間短,由哪一方來關閉,除非雙方的實現有更明確的協議
4. 如果客戶端不是httpclient,使用telnet連接服務端?
telnet客戶端除了連接時進行三次握手,用來發送數據接收數據,基本無其他實現邏輯。即接收到服務器的響應之后,不會有相關HTTP協議的處理。