Tcp Keepalive - Protocol Not Available

tcp keepalive - Protocol not available?

In an application that I coded, the following works:

setsockopt(*sfd, SOL_SOCKET, SO_KEEPALIVE,(char *)&enable_keepalive, sizeof(enable_keepalive));
setsockopt(*sfd, IPPROTO_TCP, TCP_KEEPCNT, (char *)&num_keepalive_strobes, sizeof(num_keepalive_strobes));
setsockopt(*sfd, IPPROTO_TCP, TCP_KEEPIDLE, (char *)&keepalive_idle_time_secs, sizeof(keepalive_idle_time_secs));
setsockopt(*sfd, IPPROTO_TCP, TCP_KEEPINTVL, (char *)&keepalive_strobe_interval_secs, sizeof(keepalive_strobe_interval_secs));

Try changing SOL_SOCKET to IPPROTO_TCP for TCPKEEPIDLE.

Configuring TCP keepalive after accept

Here is a minimal working example. If it works for you, you can use it as a reference.

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

#define check(expr) if (!(expr)) { perror(#expr); kill(0, SIGTERM); }

void enable_keepalive(int sock) {
int yes = 1;
check(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) != -1);

int idle = 1;
check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(int)) != -1);

int interval = 1;
check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(int)) != -1);

int maxpkt = 10;
check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(int)) != -1);
}

int main(int argc, char** argv) {
check(argc == 2);

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
check(inet_pton(AF_INET, argv[1], &addr.sin_addr) != -1);

int server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
check(server != -1);

int yes = 1;
check(setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != -1);

check(bind(server, (struct sockaddr*)&addr, sizeof(addr)) != -1);
check(listen(server, 1) != -1);

if (fork() == 0) {
int client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
check(client != -1);
check(connect(client, (struct sockaddr*)&addr, sizeof(addr)) != -1);
printf("connected\n");
pause();
}
else {
int client = accept(server, NULL, NULL);
check(client != -1);
enable_keepalive(client);
printf("accepted\n");
wait(NULL);
}

return 0;
}

Example output (tcpdump reports keepalive packets every second):

$ ./a.out 127.0.0.1 &
[1] 14010
connected
accepted

$ tcpdump -n -c4 -ilo port 12345
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
18:00:35.173892 IP 127.0.0.1.12345 > 127.0.0.1.60998: Flags [.], ack 510307430, win 342, options [nop,nop,TS val 389745775 ecr 389745675], length 0
18:00:35.173903 IP 127.0.0.1.60998 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 389745775 ecr 389745075], length 0
18:00:36.173886 IP 127.0.0.1.12345 > 127.0.0.1.60998: Flags [.], ack 1, win 342, options [nop,nop,TS val 389745875 ecr 389745775], length 0
18:00:36.173898 IP 127.0.0.1.60998 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 389745875 ecr 389745075], length 0
4 packets captured
8 packets received by filter
0 packets dropped by kernel

Is TCP Keepalive the only mechanism to determine a broken link?

Keepalive was designed to deal with so-called half-opened connections, when one of the sides (typically the server that receives the requests) is unaware that connection was broken. Client usually knows about it because the attempt to send request to the server will return you error.

Another option is to keep listener running - when client detects comms problems it just tries to connect to the server again. Server gets the incoming connection, check whether it from the same IP address, and if it is the case, closes opened connection and establishes a new one.

But if client is unaware that connection went down and server needs to send something, there is no way for server to re-establish connection but TCP keepalive.

If you don't want to use keepalive, you can use application-level keepalive, e.g. sending something like application-specific echo messages.

Does a TCP socket connection have a keep alive?

TCP sockets remain open till they are closed.

That said, it's very difficult to detect a broken connection (broken, as in a router died, etc, as opposed to closed) without actually sending data, so most applications do some sort of ping/pong reaction every so often just to make sure the connection is still actually alive.

Is TCP Keepalive necessary for a busy TCP socket?

No. TCP keepalive is practically a 0 byte-long tcp packet. If you can be sure on your app protocol, it is unneeded.

WebSockets ping/pong, why not TCP keepalive?

The problems with TCP keepalive are:

  1. It is off by default.
  2. It operates at two-hour intervals by default, instead of on-demand as the Ping/Pong protocol provides.
  3. It operates between proxies rather than end to end.
  4. As pointed out by @DavidSchwartz, it operates between TCP stacks, not between the applications so therefore it doesn't tell us whether the application is alive or not.

The comparison with WebSockets ping/pong isn't meaningful. TCP keepalive is automatic, and timed, when enabled, whereas WebSocket ping/pong is executed as required by the application.

Detecting Socket Disconnect Using TCP KeepAlive

You will not get far with the built-in keep-alives of the TCP stack. That's because the keep-alive interval cannot be tuned by your application, it is set by the OS, and the defaults are rather high (hours). This is not specific to Java.

If you need to time out in a reasonable time, you have to implement some kind of keep alive in the protocol to be used. Most of the high-level protocols I have seen have some kind of NOP functionality, where you send an "Are you there?" message and the other party sends a "Yes, I'm here" reply without doing anything else.



Related Topics



Leave a reply



Submit