Java建立长链接的方式_java http长链接(keep-alive)导致的问题
兩種由http長鏈接(keep-alive)導致的問題,當然這兩種問題都有多種原因導致,這里只分析針對keep-alive相關而產生的異常。
1 SocketException: Connection reset
報錯堆棧日志:
Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:209)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140)
復制代碼
本質原因是服務器通過TCP協議給客戶端返回了RST消息,表示已經完成了發送和接收,如果客戶端此時從流中讀取數據時會發生Connection reset,往流中寫數據時就會發生Connection reset Connection reset by peer。注意Socket.close()語義和TCP FIN消息之間略有不匹配。
而至于為什么服務端會返回RST消息,那就是http keep-alive 導致的問題了。
如果是springboot的服務器,那么默認的keep-alive timeout是60s,如果客戶端使用的是apache httpclient,默認的keep-alive是在
org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy類設置的,代碼如下:
public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
Args.notNull(response, "HTTP response");
final HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
final HeaderElement he = it.nextElement();
final String param = he.getName();
final String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
} catch(final NumberFormatException ignore) {
}
}
}
return -1;
}
復制代碼
可見,如果response header如果沒有返回Keep-Alive,那么就會是-1,也就是無限的,hc.apache.org/httpcompone… "If the Keep-Alive header is not present in the response, HttpClient assumes the connection can be kept alive indefinitely"
所以問題就比較明白了,springboot服務端沒有返回Keep-Alive的header,客戶端如果使用了apache httpclient,且沒有設置Keep-Alive的話,就會導致服務端的超時是60s,客戶端就認為是無限的,在某些情況下,服務端關閉了鏈接,客戶端還會獲取這個連接,就會導致上面的問題。
既然找到原因了那么就需要解決,httpclient文檔中也給了說要設置默認的超時時間,即給一個自定義的實現。
2 NoHttpResponseException: xxx.xxx.xxx.xxx failed to respond
Caused by: org.apache.http.NoHttpResponseException: xxx.xxx.xxx.xxx failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140)
復制代碼
補充知識點:
1 'Connection: Keep-Alive' header頭只用來在HTTP 1.0中, 而在HTTP 1.1中默認都是Keep-Alive的,所以不需要再添加'Connection: Keep-Alive'的頭。所以在springboot1.5以上版本中,即使你在請求的header中加了'Connection: Keep-Alive'的頭,在返回的header中是沒有Connection的。相關鏈接:github.com/spring-proj…
2 curl 命令可以使用--http1.0 來強制走http1.0協議。
3 springboot中 tomcat 默認的keepalive timeout是60s, github.com/spring-proj…
關于找一找教程網
本站文章僅代表作者觀點,不代表本站立場,所有文章非營利性免費分享。
本站提供了軟件編程、網站開發技術、服務器運維、人工智能等等IT技術文章,希望廣大程序員努力學習,讓我們用科技改變世界。
[java http長鏈接(keep-alive)導致的問題]http://www.zyiz.net/tech/detail-108704.html
總結
以上是生活随笔為你收集整理的Java建立长链接的方式_java http长链接(keep-alive)导致的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache POI 实现报表导入和导出
- 下一篇: 智能网关能够实现哪些功能