瀏覽器在向服務器發送請求時,有的會帶上Connection:keep-alive參數,如下圖所示:
http1.1開始支持長連接。請求的頭部會帶上keep-alive參數。長連接的作用是減少斷開連接和重新連接的開銷,提高網絡請求效率。http只是1個協議規范,具體的實現請見下文。
TCP是由操作系統實現的。而socket是由JVM封裝的。所以java可以使用socket相關的api進行網絡請求操作。下面給出測試代碼:
erverSocket serverSocket = new ServerSocket(8080, 1, InetAddress.getByName(“localhost”)); Socket socket = null; InputStream is = null; OutputStream os = null; try { socket = serverSocket.accept();//1.監聽到客戶端的連接 is = socket.getInputStream(); os = socket.getOutputStream(); Request request = Util.getRequest(is);//2.從輸入流中讀取數據,並根據Http協議轉換成請求 Response response = Util.service(request);//服務器內部根據請求信息給出響應信息 os.writeResponse(response);//3.將響應信息寫到輸出流 } catch (Exception e) { e.printStackTrace(); } finally {//4.關閉輸入輸出流及連接 if (is != null) { is.close(); } if (os != null) { os.close(); } socket.close(); }
后面的內容參考:https://www.jianshu.com/p/09e2f32a74dd By飛行員舒克_ed03
按圖索驥研究tomcat
linux下tomcat的啟動我們只要運行startup.sh
我們研究下這個文件,其中的內容如下,運行startup.sh的實際結果是運行catalina.sh還帶了參數start
#略 EXECUTABLE=catalina.sh #略 exec "$PRGDIR"/"$EXECUTABLE" start "$@"
方法中有個while循環,還有個keepAlive參數。其中有一段對keepalive的賦值改變
if (maxKeepAliveRequests == 1) { keepAlive = false; } else if (maxKeepAliveRequests > 0 && socketWrapper.decrementKeepAlive() <= 0) { keepAlive = false; }
這里的maxKeepAliveRequests 就是server配置文件里的
web.xml<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxKeepAliveRequests = 10000 />
這個參數的意思是最多經過多少個請求之后將Connection有keep-alive改為close的。
當keepAlive設為false以后,會退出循環並返回SocketState.CLOSED給調用者。調用者收到這個狀態后會關閉socket。結束連接,tcp會進行4次揮手結束會話。
假設keepAlive一開始就未設置,那么就不會進入循環,直接返回調用者SocketState.CLOSED。
如果keepAlive還沒到最大值,會一直在while的循環中,持續處理socket中的內容,直到keepAlive失效,或者連接中斷。
了解了原理之后,我們來看看我們的問題。keepAlive開啟會一直占用一個連接,直到socket關閉。tomcat有最大連接數參數是maxConnections,這個值表示最多可以有多少個socket連接到tomcat上。BIO模式下默認最大連接數是它的最大線程數(缺省是200),NIO模式下默認是10000,APR模式則是8192(windows上則是低於或等於maxConnections的1024的倍數)。如果設置為-1則表示不限制。當請求過多時,新的請求不會被接受,老的請求受網絡io的影響。但老的請求的會話被關閉的可能性還比較小。所以在搶票之類的程序中,先登入服務所在的tomcat還是有優勢的。從另一個方面來說關閉keepalive的功能對搶票人來說較公平。