日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > Linux下關于TCP的keep alive的實現源碼分析

Linux下關于TCP的keep alive的實現源碼分析

來源:程序員人生   發布時間:2015-01-23 08:45:25 閱讀次數:2614次

 TCP下的Keep Alive

我們常說的TCP的keep alive,就是為了保證連接的有效性,在間隔1定的時間發探測包,根據回復來確認該連接是不是有效。通常上層利用會自己提供心跳檢測機制,而Linux內核本身也提供了從內核層面的確保連接有效性的方式。

在sock 函數中可以設置是不是需要打開keep alive開關,默許建立socket 是關閉keep alive的。代碼以下

optval = 1; optlen = sizeof(optval); if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { perror("setsockopt()"); close(s); exit(EXIT_FAILURE); }

Keep Alive 的控制參數

tcp_keepalive_time 參數

控制keep alive的最長空閑時間

tcp_keepalive_probes 參數

當超過最長空間時間后,內核會嘗試發出探測包確認客戶端時候存活,該參數控制的是嘗試的次數

tcp_keepalive_intvl 參數

當超過最長空閑時間后,內核會發出探測包,當沒有收到確認回復的,該參數控制下個探測包的時間

Linux下如何實現Keep Alive

sock結構體中的timer_list

在sock結構體中,存在timer_list的結構體sk_timer,參考下面結構

struct sock{ ... struct timer_list sk_timer; ... }
struct timer_list { struct list_head entry; unsigned long expires; void (*function)(unsigned long); unsigned long data; struct tvec_base *base; #ifdef CONFIG_TIMER_STATS void *start_site; char start_comm[16]; int start_pid; #endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map; #endif };
timer_list結構體,是在sock里經常使用的timer履行鏈表,entry代表的是鏈表的頭, expires代表的失效時間,而function就是履行的函數。

注冊keepalive處理函數

void inet_csk_init_xmit_timers(struct sock *sk, void (*retransmit_handler)(unsigned long), void (*delack_handler)(unsigned long), void (*keepalive_handler)(unsigned long)) { struct inet_connection_sock *icsk = inet_csk(sk); setup_timer(&icsk->icsk_retransmit_timer, retransmit_handler, (unsigned long)sk); setup_timer(&icsk->icsk_delack_timer, delack_handler, (unsigned long)sk); setup_timer(&sk->sk_timer, keepalive_handler, (unsigned long)sk);//注冊了函數在sk_timer中 icsk->icsk_pending = icsk->icsk_ack.pending = 0; }

當連接完成的時候(也就是握手成功的時候),在新生成的sock里面的sk_timer結構體中,注冊了函數keepalive_handler函數

void tcp_init_xmit_timers(struct sock *sk) { inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, &tcp_keepalive_timer); }

而keepalive_handler函數就是tcp_keepalive_timer函數

static void tcp_keepalive_timer (unsigned long data) { ...... if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE) goto out; elapsed = keepalive_time_when(tp); /* It is alive without keepalive 8) */ if (tp->packets_out || tcp_send_head(sk)) goto resched; elapsed = tcp_time_stamp - tp->rcv_tstamp; if (elapsed >= keepalive_time_when(tp)) { if (icsk->icsk_probes_out >= keepalive_probes(tp)) { tcp_send_active_reset(sk, GFP_ATOMIC); tcp_write_err(sk); goto out; } if (tcp_write_wakeup(sk) <= 0) { icsk->icsk_probes_out++; elapsed = keepalive_intvl_when(tp); } else { /* If keepalive was lost due to local congestion, * try harder. */ elapsed = TCP_RESOURCE_PROBE_INTERVAL; } } else { /* It is tp->rcv_tstamp + keepalive_time_when(tp) */ elapsed = keepalive_time_when(tp) - elapsed; } ..... }

上面只是截取了1部份代碼,重點是前面提到的參數的實現,代碼首先先檢查了是不是在sock里設置了參數SO_KEEPALIVE,也就是sock里面的flag:SOCK_KEEPOPEN。

如果設置了socket的SO_KEEPALIVE,才繼續檢查時間戳,取的上次收到包的時間戳和當前時間戳的差值,進行和參數keepalive_time的比較,如果已超時了,那末檢查發已出探測包失敗的次數,如果次數已比keepalive_probes的大,那末發出reset包,同時寫毛病報告,關閉sock。

 如果比設置的探測包次數小的話,那發出探測包,同時設置下次的校驗的時間戳為keepalive_intvl, 而不在是keepalive_time。

注意:在這里keepalive_intvl只是控制觸發下次校驗的時間

計算結束無效連接的時間N會有兩種情況

a.  keepalive_intvl 的時間比 keepalive_time 大

N=keepalive_time +keepalive_intvl*keepalive_probes

b. keepalive_intvl 的時間比 keepalive_time小

N=keepalive_time +keepalive_time*keepalive_probes

這也就是為何在默許設置里,認為無效的連接的時間實際上是7200*6 要12小時才會斷掉連接

代碼中設置keepalive_time,keepalive_probes,keepalive_intvl

setsockopt(s, SOL_TCP, TCP_KEEPIDLE, &val, sizeof(int)) setsockopt(s, SOL_TCP, TCP_KEEPINTVL, &val, sizeof(int)) setsockopt(s, SOL_TCP, TCP_KEEPCNT, &val, sizeof(int))

所對應的3個參數 TCP_KEEPIDLE  --> keepalive_time, TCP_KEEPINTVL--> keepalive_intvl, TCP_KEEPCNT--> keepalive_probes
3個參數本身也有最大值的保護,TCP_KEEPIDLE 最大是32767 TCP_KEEPINTVL 最大值是32767 TCP_KEEPCNT 最大值是127

JAVA中并沒有提供對這些參數的修改

處理中的定時器

而TCP連接進程中,會有很多的定時器timer,做1些定時的檢查,比如前面的博客里提到的清除accept queue的定時器,ack的定時器,有興趣的可以參考tcp_timer.c
定時器的主要作用就是在固定時的狀態下進行程序調用,在keep alive中就是定時發送探測包以肯定包的有效性。

JAVA設置Keep alive


Java 里只允許打開keep alive,但卻不允許設置keep alive的幾個相干參數,Java 對客戶端中打開keep alive直接調用Socket.setKeepAlive函數,而在服務器真個ServerSocket 卻不允許設置keep alive的開關,你只能在accept 1個新的連接的socket 的時候設置。

如何能設置剛才的需要的參數在java中?這里只是提1個思路

在java里的最后JNI的調用中,設置了常量數組的保護,只有數組中的參數才被允許設置到socket中
const opts[] = { { java_net_SocketOptions_TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY }, { java_net_SocketOptions_SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE }, { java_net_SocketOptions_SO_LINGER, SOL_SOCKET, SO_LINGER }, { java_net_SocketOptions_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF }, { java_net_SocketOptions_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF }, { java_net_SocketOptions_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE }, { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR }, { java_net_SocketOptions_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST }, { java_net_SocketOptions_IP_TOS, IPPROTO_IP, IP_TOS }, { java_net_SocketOptions_IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF }, { java_net_SocketOptions_IP_MULTICAST_IF2, IPPROTO_IP, IP_MULTICAST_IF }, { java_net_SocketOptions_IP_MULTICAST_LOOP, IPPROTO_IP, IP_MULTICAST_LOOP }, };

直接設置是沒有辦法了,但可以用自己寫JNI的方法來添加,由于在socket里有FileDescriptor fd,而里面的int fd 就是對應到內核中socket的 fd, 只要拿到這個fd 就能夠調用自己的native方法來設置需要的參數,固然你也能夠寫自己的 socket, 來封裝1個寫setsocketoption的native 函數。


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 日韩三级 | 国产精品久久久久久久久久免 | 亚洲精品乱码久久久久久蜜糖图片 | 精品久久久一区二区 | 国产尤物一区 | 成人一区二区三区四区 | 国产在线播放一区 | 91在线免费看 | av三级在线观看 | 欧美一区二区三区视频 | 亚洲欧美日韩国产综合 | 亚洲国产欧美在线 | 日韩一二三 | 中国一级毛片在线播放 | 国产精品v欧美精品v日韩精品 | 亚洲a网站 | 国产精品免费看 | 蜜桃精品久久久久久久免费影院 | 色综合网在线 | 自拍偷拍欧美日韩 | 亚洲综合无码一区二区 | 免费中文视频 | 久久国产精品二国产精品 | 日本伊人网 | 国产精品久久久久久久久久久久久 | 五月婷婷综合在线 | 欧美日韩免费一区 | 国产精品毛片无码 | 国产精品久久久久久福利一牛影视 | 国产在线一二三四区 | 国v精品久久久网 | 久久久久久久久99精品大 | 91久久精品一区 | 亚洲视频在线观看免费 | 国产精品18 | 激情综合激情五月 | av片在线观看 | av在线免费网址 | 久久久99国产精品免费 | 成人免费在线电影 | 欧美天天干|