# Keep-Alive ## 作用 * 重複利用已建立連線,減少每次建立連線交握時間 * 不正常結束連線時,port 無法及時釋放,導致占用 * [windows](https://learn.microsoft.com/zh-tw/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance) ## Keep-Alive max 沒有作用 透過 __HttpURLConnection__ 發送請求時,發現 __KeepAliveCache__ 最多只保存 5 個連線 * __sun.net.www.http.KeepAliveCache__ 用來緩存 __HttpClient__ 的容器 * 設定上限(預設 __5__ ) ``` -Dhttp.maxConnections=N ``` * __getMaxConnections()__ ```java static int getMaxConnections() { if (result == -1) { result = AccessController.doPrivileged( new GetIntegerAction("http.maxConnections", MAX_CONNECTIONS)) .intValue(); if (result <= 0) { result = MAX_CONNECTIONS; } } return result; } ``` * __put__ ```java synchronized void put(HttpClient h) { if (size() >= KeepAliveCache.getMaxConnections()) { h.closeServer(); // otherwise the connection remains in limbo } else { push(new KeepAliveEntry(h, System.currentTimeMillis())); } } ``` * __sun.net.www.http.HttpClient__ 透過解析 __Response Header__ 決定緩存連線使用次數,但是 __keepAliveConnections__ 每次都會被更新為 __5__ 怪怪的。 * __parseHTTPHeader__ ```java HeaderParser p = new HeaderParser(responses.findValue("Keep-Alive")); /* default should be larger in case of proxy */ keepAliveConnections = p.findInt("max", usingProxy?50:5); keepAliveTimeout = p.findInt("timeout", usingProxy?60:5); ``` * __finished__ ```java public void finished() { if (reuse) /* will be reused */ return; keepAliveConnections--; poster = null; if (keepAliveConnections > 0 && isKeepingAlive() && !(serverOutput.checkError())) { /* This connection is keepingAlive && still valid. * Return it to the cache. */ putInKeepAliveCache(); } else { closeServer(); } } ``` ## Spring Boot & Tomcat * 配置 __yml__ ```yml server: tomcat: uri-encoding: UTF-8 max-keep-alive-requests: 500 // 沒有作用 keep-alive-timeout: 99s ``` * __org.apache.coyote.http11.Http11Processor__ 雖然配置了 `max-keep-alive-requests`,但是只用來檢查是否關閉 __Keep Alive__ ,沒有如預期回覆 `Keep-Alive: max=500; timeout=99`,但是 __max__ 已被棄用。 [RFC](https://datatracker.ietf.org/doc/html/draft-thomson-hybi-http-timeout-03#section-2.2.1) * __service__ ```java int maxKeepAliveRequests = protocol.getMaxKeepAliveRequests(); if (maxKeepAliveRequests == 1) { keepAlive = false; } else if (maxKeepAliveRequests > 0 && socketWrapper.decrementKeepAlive() <= 0) { keepAlive = false; } ``` * __prepareResponse__ ```java if (connectionKeepAlivePresent) { int keepAliveTimeout = protocol.getKeepAliveTimeout(); if (keepAliveTimeout > 0) { String value = "timeout=" + keepAliveTimeout / 1000L; headers.setValue(Constants.KEEP_ALIVE_HEADER_NAME).setString(value); if (http11) { // Append if there is already a Connection header, // else create the header MessageBytes connectionHeaderValue = headers.getValue(Constants.CONNECTION); if (connectionHeaderValue == null) { headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN); } else { connectionHeaderValue.setString( connectionHeaderValue.getString() + ", " + Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN); } } } } ``` ## 總結 __Client__ 需要設置 `http.maxConnections` 才不會發生以下錯誤。 ``` java.net.BindException: Address already in use ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up