Keep Alive under TCP
We often say that the TCP keep alive, is to ensure the validity of the connection, at a certain time interval to send a probe packet, based on the reply to confirm that the connection is valid. Typically, upper-level applications provide their own heartbeat detection mechanisms, and the Linux kernel itself provides a way to ensure connection effectiveness from the core.
In the sock function, you can set whether you need to open the keep alive switch, and the default socket is to turn off keep alive. The code is as follows
Optval = 1; Optlen = sizeof (optval); if (setsockopt (S, Sol_socket, So_keepalive, &optval, Optlen) < 0) { perror ("setsockopt ()"); Close (s); Exit (exit_failure); }
Control parameters of Keep Alive
Tcp_keepalive_time parameter controls maximum idle time for keep alive
Tcp_keepalive_probes parameters
When the maximum space time is exceeded, the kernel attempts to emit a probe packet to confirm that the client is alive, and this parameter controls the number of attempts
TCP_KEEPALIVE_INTVL parameter when the maximum idle time is exceeded, the kernel emits a probe packet, which controls the time of the next probe packet when no acknowledgement is received.
How to implement the timer_list in Keep alivesock structure under Linux
In the sock structure, there is a timer_list structure sk_timer, refer to the following structure
struct Sock{...struct timer_listsk_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_statsvoid *start_site;char start_comm[16];int start_pid; #endif #ifdef Config_lockdepstruct lockdep_map lockdep_map; #endif};
Timer_list structure, is commonly used in the sock timer execution chain list, entry represents the head of the list, expires represents the failure time, and function is the execution of functions.
Registering keepalive processing functions
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);//Registered function in Sk_timer icsk->icsk_pending = icsk->icsk_ack.pending = 0;}
When the connection is complete (that is, when the handshake succeeds ), the function Keepalive_handler function is registered in the Sk_timer structure of the newly generated sock.
void Tcp_init_xmit_timers (struct sock *sk) {inet_csk_init_xmit_timers (SK, &tcp_write_timer, &tcp_delack_ Timer, &tcp_keepalive_timer);}
And the Keepalive_handler function is the Tcp_keepalive_timer function.
static void Tcp_keepalive_timer (unsigned long data) {... if (!sock_flag (SK, sock_keepopen) | | sk->sk_state = TCP_CL OSE) Goto out;elapsed = Keepalive_time_when (TP);/* It is alive without keepalive 8) */if (Tp->packets_out | | tcp_send_he AD (SK)) goto resched;elapsed = tcp_time_stamp-tp->rcv_tstamp;if (elapsed >= keepalive_time_when (TP)) {if (icsk-& Gt;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;} .....}
Above just intercept a part of the code, the focus is the implementation of the parameters mentioned earlier, the code first check whether the parameter is set in the SOCK so_keepalive, that is, SOCK inside the Flag:sock_keepopen.
If the socket is set to the so_keepalive, only to continue to check the timestamp, the last time the packet received the timestamp and the current timestamp difference, and the parameter keepalive_time comparison, if already timed out, then check the hair has been out of the number of detection packet failure, If the number of times is already larger than Keepalive_probes, then issue the reset package, write the error report, and close the sock.
If the number of probe packets is smaller than the set, then the probe packet is sent, and the timestamp of the next check is set to KEEPALIVE_INTVL, not keepalive_time.
Note: Here KEEPALIVE_INTVL only controls when the next check is triggered
Calculate the time to end an invalid connection n there are two things
A. KEEPALIVE_INTVL time is bigger than keepalive_time.
n= keepalive_time +keepalive_intvl*keepalive_probes
B. KEEPALIVE_INTVL time is smaller than keepalive_time
n= keepalive_time +keepalive_time*keepalive_probes
This is why in the default setting, it is considered that the time of the invalid connection is actually 7200*6 to 12 hours before the connection code is disconnected from the settings 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))
The corresponding 3 parameters tcp_keepidle---Keepalive_time, tcp_keepintvl--> KEEPALIVE_INTVL, tcp_keepcnt--> keepalive_ The PROBES3 parameter itself also has a maximum value of protection, Tcp_keepidle maximum is 32767 TCP_KEEPINTVL maximum is 32767 tcp_keepcnt maximum is 127
modifications to these parameters are not available in Java
Processing timers While the TCP connection process, there will be a lot of timer timer, do some timed check, such as mentioned in the previous blog to clear the Accept queue timer, ACK timer, interested can refer to Tcp_ The main function of the TIMER.C timer is to make the program call in the fixed state, and in the keep alive, it is timed to send the probe packet to determine the validity of the packet.
Java Settings Keep alive
Java is only allowed to open keep alive, but does not allow the setting of keep alive a few related parameters, Java for the client to open keep alive directly call socket.setkeepalive function, and on the server side ServerSocket It is not allowed to set the keep alive switch, you can only set it when you accept a new connected socket.
How can I set just the required parameters in Java? Here's just a thought.
In the last JNI call in Java, the protection of the constant array is set, only the parameters in the array are allowed to be set to the socket
Const opts[] = {{Java_net_socketoptions_tcp_nodelay, ipproto_tcp, Tcp_nodelay}, {java_net_s Ocketoptions_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_reusead DR}, {java_net_socketoptions_so_broadcast, Sol_socket, so_broadcast}, {Java_net_socketoptio Ns_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}, {JAV A_net_socketoptions_ip_mUlticast_loop, Ipproto_ip, Ip_multicast_loop},};
Direct Setup is no way, but can be used to write Jni method to add, because there is filedescriptor FD in the socket, and the inside of the int FD is corresponding to the core socket of the FD, as long as get this FD You can call your own native method to set the required parameters, and of course you can write your own socket to encapsulate a native function that writes SetSocketOption.
Implementation of keep alive for TCP under Linux source code analysis