使客戶端到服務器端的鏈接持續有效,當出現對服務器的後繼請求時,Keep-Alive功能避免了創建或者從新創建鏈接。
HTTP/1.0中默認使用Connection:close, 在HTTP/1.1中已經默認使用Connection: keep-alive。TCP協議層默認並不開啓KeepAlive功能。
java
http1.1中因默認支持長鏈接,因此若是不但願使用則須要在header中指明connection的值爲close;而server也不想支持,則在response中也須要明確說明connection的值爲close。
HTTP Connection的 close設置容許客戶端或服務器中任何一方關閉底層的鏈接時雙方都會要求在處理請求後關閉它們的TCP鏈接。即不管request仍是response的header中包含了值爲close的connection,都代表當前正在使用的tcp連接在請求處理完畢後會被斷掉,之後client再進行新的請求時就必須建立新的tcp連接了。(程序中能夠在過濾器中加入:response.setHeader("connection", "close");)
瀏覽器在請求頭部添加 Connection:keep-alive,以此告知服務器本身支持長鏈接方式,而假若服務器也支持,那麼就在響應頭部添加 Connection:keep-alive,從而告訴瀏覽器長鏈接。服務器還能夠經過 Keep-Alive:timeout=10, max=100 的頭部告訴瀏覽器「10 秒算超時時間,最長不能超過 100 秒」。 客戶端和服務端均可以設置timeout和max屬性值,但http鏈接保持時間是由服務端的消息頭connection字段和keep-alive字段定的!linux
//org.apache.http.impl.execchain.MainClientExec#execute ...... //從鏈接池中lease connection final HttpClientConnectionmanagedConn = connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS); ...... //將conenction封裝在ConnectionHolder中 final ConnectionHolder connHolder = new ConnectionHolder(this.log, this.connManager, managedConn); ...... // The connection is in or can be brought to a re-usable state. //若是返回值消息頭中connection設置爲close,則返回false if (reuseStrategy.keepAlive(response, context)) { // Set the idle duration of this connection //取出response消息頭中,keep-alive的timeout值 final long duration = keepAliveStrategy.getKeepAliveDuration(response, context); if (this.log.isDebugEnabled()) { final String s; if (duration > 0) { s = "for " + duration + " " + TimeUnit.MILLISECONDS; } else { s = "indefinitely"; } this.log.debug("Connection can be kept alive " + s); } //設置失效時間 connHolder.setValidFor(duration, TimeUnit.MILLISECONDS); connHolder.markReusable(); } else { connHolder.markNonReusable(); }
http keep-alive 意圖在於鏈接複用。是爲了讓TCP存活更久以便複用TCP鏈接,在一個TCP鏈接上進行屢次的HTTP請求從而提升性能。
tcp KeepAlive是TCP的一種檢測TCP鏈接情況的保鮮機制, 意圖在於保活、心跳,檢測鏈接錯誤。
TCP通常而言爲服務器端提供保活功能: 若是客戶端已經消失,使得服務器上保留一個半開放的鏈接,而服務器又在等待來自客戶端的數據,則服務器將永遠等待客戶端的數據, 保活功能就是試圖在服務器端檢測到這種半開放的鏈接。nginx
及時有效地檢測到一方的非正常斷開,保證鏈接的資源被有效利用。apache
Tomcat中的相關設置,在conf/server.xml 中的Connector 元素中: keepAliveTimeout: The number of milliseconds this Connector will wait for another HTTP request before closing the connection. The default value is to use the value that has been set for the connectionTimeout attribute. maxKeepAliveRequests: The maximum number of HTTP requests which can be pipelined until the connection is closed by the server. Setting this attribute to 1 will disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1 will allow an unlimited amount of pipelined or keep-alive HTTP requests. If not specified, this attribute is set to 100.
int keepAlive = 1; // 開啓keepalive屬性. 缺省值: 0(關閉) int keepIdle = 60; // 若是在60秒內沒有任何數據交互,則進行探測. 缺省值:7200(s) int keepInterval = 5; // 探測時發探測包的時間間隔爲5秒. 缺省值:75(s) int keepCount = 2; // 探測重試的次數. 所有超時則認定鏈接失效..缺省值:9(次) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive)); setsockopt(s, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle)); setsockopt(s, SOL_TCP, TCP_KEEPINTVL, (void*)&keepInterval, sizeof(keepInterval)); setsockopt(s, SOL_TCP, TCP_KEEPCNT, (void*)&keepCount, sizeof(keepCount)); // TCP_KEEPCNT : 覆蓋 tcp_keepalive_probes ; // TCP_KEEPIDLE : 覆蓋tcp_keepalive_time ; // TCP_KEEPINTVL : 覆蓋 tcp_keepalive_intvl int keepAlive = 1;
#cat /proc/sys/net/ipv4/tcp_keepalive_time 7200 #cat /proc/sys/net/ipv4/tcp_keepalive_intvl 75 #cat /proc/sys/net/ipv4/tcp_keepalive_probes 9 #echo 60 > /proc/sys/net/ipv4/tcp_keepalive_time #echo 5 > /proc/sys/net/ipv4/tcp_keepalive_intvl #echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes全局設置可更改/etc/sysctl.conf, 使用 sudo sysctl -p當即生效;(永久有效)
net.ipv4.tcp_keepalive_intvl = 20 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.tcp_keepalive_time = 60
表示實體內容的長度。瀏覽器經過這個字段來判斷當前請求的數據是否已經所有接收。c#
因此,當瀏覽器請求的是一個靜態資源時,即服務器能明確知道返回內容的長度時,能夠設置Content-Length
來控制請求的結束。但當服務器並不知道請求結果的長度時,如一個動態的頁面或者數據,Content-Length
就沒法解決上面的問題,這個時候就須要用到Transfer-Encoding
字段。windows
表示傳輸編碼。
還有一個相似的字段叫作:Content-Encoding
。區別是Content-Encoding
用於對實體內容的壓縮編碼(Content-Encoding: gzip
); Transfer-Encoding
則改變了報文的格式。
當服務端沒法知道實體內容的長度時,可指定Transfer-Encoding:chunked
(還可同時指定Transfer-Encoding: gzip
),
代表實體內容數據不只是gzip壓縮的,仍是分塊傳遞的。最終當瀏覽器接收到一個長度爲0的chunked時, 標識當前請求內容已所有接收。瀏覽器
分塊編碼, 標識將數據分紅一塊一塊的發出。Chunked編碼將使用若干個Chunk串連而成,由一個標明長度爲0 的chunk標示結束。
chunk-size指定十六進制的數字表明後面chunk-data的字節長度,若是是「0」,則表示chunk-size爲0,該chunk爲last-chunk,無chunk-data部分。服務器
Chunked-Body = *chunk //0至多個chunk last-chunk //最後一個chunk trailer //尾部 CRLF //結束標記符 chunk = chunk-size [ chunk-extension ] CRLF chunk-data CRLF // 單個chunk內容 chunk-size = 1*HEX last-chunk = 1*("0") [ chunk-extension ] CRLF chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token | quoted-string chunk-data = chunk-size(OCTET) trailer = *(entity-header CRLF)
一、Content-Length若是存在而且有效的話,則必須和消息內容的傳輸長度徹底一致。(若是太短則會截斷,過長則會致使超時)socket
二、若是存在Transfer-Encoding(重點是chunked),則在header中的Content-Length會被忽視。tcp
三、若是採用短鏈接,則直接能夠經過服務器關閉鏈接來肯定消息的傳輸長度。