linux網路程式設計 keepalive

2021-07-10 23:47:12 字數 4045 閱讀 8430

我們說到keepalive的時候,需要先明確一點,這個keepalive說的是tcp的還是http的。

一、tcp keepalive

tcp的keepalive是側重在保持客戶端和服務端的連線,一方會不定期傳送心跳包給另一方,當一方斷掉的時候,沒有斷掉的定時傳送幾次心跳包,如果間隔傳送幾次,對方都返回的是rst,而不是ack,那麼就釋放當前鏈結。設想一下,如果tcp層沒有keepalive的機制,一旦一方斷開連線卻沒有傳送fin給另外一方的話,那麼另外一方會一直以為這個連線還是存活的,幾天,幾月。那麼這對伺服器資源的影響是很大的。

tcp_keepalive_time // 距離上次傳送資料多少時間未收到判斷為開始檢測

tcp_keepalive_intvl // 檢測開始每多少時間傳送心跳包

tcp_keepalive_probes // 傳送幾次心跳包對方未響應則close連線

解釋:

當tcp發現有tcp_keepalive_time(7200)秒未收到對端資料後,開始以間隔tcp_keepalive_intvl(75)秒的頻率傳送的空心跳包,如果連續tcp_keepalive_probes(9)次以上未響應**對端已經down了,close連線。

流程:

在客戶端和服務端進行完三次握手之後,客戶端和服務端都處在establish狀態,這個時候進行正常的psh和ack互動,但是一旦一方服務中斷了,另一方在距離上次psh時間tcp_keepalive_time發現對方未傳送資料,則開始心跳檢測。心跳檢測實際就是傳送乙個psh的空心跳包,這裡說的空心跳包就是包的資料為空,但是tcp包的頭部的資料和標識和正常包一樣。如果這個包獲取到的是rst返回的話,下面就會繼續每隔tcp_keepalive_intval的時長傳送乙個空心跳包,如果tcp_keepalive_probes次心跳包對方都是返回rst而不是ack,則心跳發起方就判斷這個連線已經失效,主動clost這個連線。

這三個引數可以每個tcp連線都不同,使用tcp設定變數的函式可以設定當前tcp連線的這三個對應的值。

int setsockopt(int s, int level, int optname,

const void *optval, socklen_t optlen)

我們要修改上面三個值,既可以修改核心引數,也可以修改**控制

**如下:

opt = 1;

setsockopt(listenfd, sol_socket, so_keepalive, (void*)&opt, sizeof(opt));

opt = 1000;

setsockopt(listenfd, sol_tcp, tcp_keepidle, (void *)&opt, sizeof(opt)); //tcp_keepalive_time

opt = 10;

setsockopt(listenfd, sol_tcp,tcp_keepintvl, (void *)&opt, sizeof(opt)); //tcp_keepalive_intvl

opt = 10;

setsockopt(listenfd,sol_tcp, tcp_keepcnt, (void *)&opt, sizeof(opt)); //tcp_keepalive_probes

tcp層的keepalive會在兩個場景下比較有用:

檢測連線的一方是否斷了

這裡說的連線的一方是否斷了包含幾種情況:

連線一方服務中止

網路不好導致的服務長時間無響應

連線一方服務重啟中

結合這三種方式就很好理解為什麼會有 tcp_keepalive_time, tcp_keepalive_intval, tcp_keepalive_probes三種的設定了。如果是對方伺服器進行重啟的時候,我們不能根據一次的tcp返回重置訊號就判定這個連線失效。相反的,重啟之後,這個心跳包一旦正常,這個連線仍然可以繼續使用。

如何判斷tcp連線是否斷開

當tcp檢測到對端socket不再可用時(不能發出探測包,或探測包沒有收到ack的響應包),select會返回socket可讀,並且在recv時返回-1,同時置上errno為etimedout。

普通的http連線是客戶端連線上服務端,然後結束請求後,由客戶端或者服務端進行http連線的關閉。下次再傳送請求的時候,客戶端再發起乙個連線,傳送資料,關閉連線。這麼個流程反覆。但是一旦客戶端傳送connection:keep-alive頭給服務端,且服務端也接受這個keep-alive的話,兩邊對上暗號,這個連線就可以復用了,乙個http處理完之後,另外乙個http資料直接從這個連線走了。

http層的keep-alive, 它主要是用於客戶端告訴服務端,這個連線我還會繼續使用,在使用完之後不要關閉。

再說keep-alive之前,先說說http的短連線/長連線。

短連線

所謂短連線,就是每次請求乙個資源就建立連線,請求完成後連線立馬關閉。每次請求都經過「建立tcp連線->請求資源->響應資源->釋放連線」這樣的過程

長連線

所謂長連線,就是只建立一次連線,多次資源請求都復用該連線,完成後關閉。要請求乙個頁面上的十張圖,只需要建立一次tcp連線,然後依次請求十張圖,等待資源響應,釋放連線。

keep-alive

具體client和server要從短連線到長連線最簡單演變需要做如下改進:

client發出的http請求頭需要增加connection:keep-alive欄位

web-server端要能識別connection:keep-alive欄位,並且在http的response裡指定connection:keep-alive欄位,告訴client,我能提供keep-alive服務,並且"應允"client我暫時不會關閉socket連線

在http/1.0裡,為了實現client到web-server能支援長連線,必須在http請求頭里顯示指定

connection:keep-alive

在http/1.1裡,就預設是開啟了keep-alive,要關閉keep-alive需要在http請求頭里顯示指定

connection:close

現在大多數瀏覽器都預設是使用http/1.1,所以keep-alive都是預設開啟的。一旦client和server達成協議,那麼長連線就建立好了。

效能

這個設定首先會在效能上對客戶端和伺服器端效能上有一定的提公升。很好理解的是少了tcp的三次握手和四次揮手,第二次傳遞資料就可以通過前乙個連線直接進行資料互動了。當然會提公升服務效能了。

伺服器time_wait的時間

由於http服務的發起方一般都是瀏覽器,即客戶端。但是先執行完邏輯,傳輸完資料的一定是服務端。那麼一旦沒有keep-alive機制,服務端在傳送完資料之後會率先發起連線斷開的操作。由於tcp的四次揮手機制,先發起連線斷開的一方會在連線斷開之後進入到time_wait的狀態達到2msl之久。設想,如果沒有開啟http的keep-alive,那麼這個time_wait就會留在服務端,由於服務端資源是非常有限的,我們當然傾向於服務端不會同一時間hold住過多的連線,這種time_wait的狀態應該盡量在客戶端保持。那麼這個http的keep-alive機制就起到非常重要的作用了。

所以基本上基於這兩個原因,現在的瀏覽器發起web請求的時候,都會帶上connection:keep-alive的頭了。

3、總結

tcp的keepalive機制和http的keep-alive機制是說的完全不同的兩個東西,tcp的keepalive是在establish狀態的時候,雙方如何檢測連線的可用行。而http的keep-alive說的是如何避免進行重複的tcp三次握手和四次揮手的環節。

Linux網路程式設計

linux網路程式設計 當然,我們現在,將要開始編寫的第乙個網路程式,雖然非常簡單,但是卻可以很 清楚的說明大部分編寫網路程式需要的基本概念,好了先讓我們看看網路程式的tcp服 務器端的編寫步驟 1.和伺服器的步驟一樣。2.通過設定套介面位址結構,我們說明,客戶端要與之通訊的伺服器的ip位址和 埠。...

linux 網路程式設計

當然,我們現在,將要開始編寫的第乙個網路程式,雖然非常簡單,但是卻可以很 清楚的說明大部分編寫網路程式需要的基本概念,好了先讓我們看看網路程式的tcp服 務器端的編寫步驟 現在讓我們來看看網路程式客戶端的程式設計步驟 以上的步驟,是比較普遍的,我們可以從中看出,編寫網路程式是很有意思的,同 時,也不...

linux 網路程式設計

套接字程式設計 struct sockaddr unsigned short sa family 位址協議,ipv4 tcp ip af inet,ipv6 af inet6 char sa data 14 14位元組的位址協議 struct sockaddr in unsigned short s...