9.7.1 Why
当单工模式下TCP数据发送方发送了一些数据后就不再发数据,数据接收方也不会发送报文,这时TCP连接处于静止状态(比如Telnet应用)。保活功能可以使用保活定时器向对端发送探测报文来确定对端的连接是否正常,如果对端有回应则继续维持连接,否则关闭连接,释放资源。开启保活功能需要使用SO_KEEPALIVE socket选项。
9.7.2 When
设置保活定时器的时机主要有三个:
(1)客户端发送SYN后收到SYN|ACK,调用tcp_finish_connect函数完成连接时:
5291 void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
5292 {
5293 struct tcp_sock *tp = tcp_sk(sk);
5294 struct inet_connection_sock *icsk = inet_csk(sk);
5295
5296 tcp_set_state(sk, TCP_ESTABLISHED);
...
5317 if (sock_flag(sk, SOCK_KEEPOPEN)) //应用进程开启keepalive服务
5318 inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));
...
5373 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
5374 const struct tcphdr *th, unsigned int len)
5375 {
...
5480 tcp_finish_connect(sk, skb);
...
(2)服务器端发送SYN|ACK后收到合法的ACK,调用
tcp_create_openreq_child
创建子socket时:
381 struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb)
382 {
383 struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
384
385 if (newsk != NULL) {
...
441 if (sock_flag(newsk, SOCK_KEEPOPEN)) //应用进程开启keepalive服务
442 inet_csk_reset_keepalive_timer(newsk,
443 keepalive_time_when(newtp));
...