TCP keepalive長連接心跳保活
比如:客戶端與服務端進行握手時,經常無法握手成功,收不到回復; 需要建立保活機制。
1. 服務端Linux服務器新增系統內核參數配置。
在/etc/sysctl.conf文件中再添加如:
#允許的持續空閑時長,在TCP保活打開的情況下,最後一次數據交換到TCP發送第一個保活探測包的間隔,即允許的持續空閑時長,或者說每次正常發送心跳的周期,默認值為7200s(2h)。 net.ipv4.tcp_keepalive_time=1800 #在tcp_keepalive_time之後,沒有接收到對方確認,繼續發送保活探測包的發送頻率, net.ipv4.tcp_keepalive_intvl=30 #在tcp_keepalive_time之後,沒有接收到對方確認,繼續發送保活探測包次數 net.ipv4.tcp_keepalive_probes=3
執行sysctl -p來使它生效:
檢測一下是否已經生效:sysctl -a | grep keepalive
2. Java/netty服務器中配置使用
ServerBootstrap bootstrapHttp =new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); bootstrapHttp.setPipelineFactory(new HttpServerPipelineFactory()); bootstrapHttp.setOption("child.tcpNoDelay", true); bootstrapHttp.setOption("child.keepAlive", true); bootstrapHttp.bind(new InetSocketAddress(ip, http_port));
3.關閉tcp_timestamps選項
客戶在服務端開啟了某個端口,但是在客戶端telnet確一直不通。通過在服務端抓包發現,客戶端的syn分節已經到達,但是服務端並沒有應答。
net.ipv4.tcp_tw_recycle選項可能引起這個問題,於是關閉了這個選項,問題果然得以解決。這裏分析一下原因。
有些服務器(當然客戶端也可以)為了避免TIME_WAIT狀態占用連接,希望能加快TIME_WAIT狀態的回收,通常將net.ipv4.tcp_tw_recycle選項開啟。
當然這個選項的生效要依賴net.ipv4.tcp_timestamps選項的開啟。雖然開啟這個選項能夠加快TIME_WAIT連接的回收,但卻引入了另一個問題。我們先看下tcp_tw_recycle選項的工作機制:
當開啟了tcp_tw_recycle選項後,當連接進入TIME_WAIT狀態後,會記錄對應遠端主機最後到達分節的時間戳。如果同樣的主機有新的分節到達,且時間戳小於之前記錄的時間戳,即視為無效,相應的數據包會被丟棄(rfc1323)。
Linux是否啟用這種行為取決於tcp_timestamps和tcp_tw_recycle,因為tcp_timestamps缺省就是開啟的,所以當tcp_tw_recycle被開啟後,實際上這種行為就被激活了
在/etc/sysctl.conf文件中再添加如:
#不檢查請求的時間戳
net.ipv4.tcp_timestamps=0
TCP keepalive長連接心跳保活