38

In my python script, I have activate TCP Keepalive using this command:

x = s.setsockopt( socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

My goal is for socket connection to get closed, if there is no transmission(*) for 5 minutes. I am working on Windows and my python script is only receiving and not transmitting any data to client program.

What I know is, by default, if no transmission will be there for 2 hours, then only I can close the connection using try and except. I know, for windows, I can manually reduce this waiting time by going to registry. But is there is a way by which, I can modify it from my script?

(*) here "no transmission" means "something quietly eats packets on the network" rather than "I'm not trying to send anything."

Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120
John
  • 381
  • 1
  • 3
  • 4

3 Answers3

73

You can set the TCP keepalive timers on an already-open socket using setsockopt().

import socket

def set_keepalive_linux(sock, after_idle_sec=1, interval_sec=3, max_fails=5):
    """Set TCP keepalive on an open socket.

    It activates after 1 second (after_idle_sec) of idleness,
    then sends a keepalive ping once every 3 seconds (interval_sec),
    and closes the connection after 5 failed ping (max_fails), or 15 seconds
    """
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle_sec)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval_sec)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails)

def set_keepalive_osx(sock, after_idle_sec=1, interval_sec=3, max_fails=5):
    """Set TCP keepalive on an open socket.

    sends a keepalive ping once every 3 seconds (interval_sec)
    """
    # scraped from /usr/include, not exported by python's socket module
    TCP_KEEPALIVE = 0x10
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    sock.setsockopt(socket.IPPROTO_TCP, TCP_KEEPALIVE, interval_sec)

For equivalent options on windows refer to msdn. Looking through the Python source, it seems you need to set SO_KEEPALIVE with sock.setsockopt similar to in Unix, and [optionally?] set SIO_KEEPALIVE_VALS with sock.ioctl.

vinod
  • 2,358
  • 19
  • 26
Will Pierce
  • 1,998
  • 20
  • 13
  • 2
    Note that the TCP_* constants used here are specific to Linux. For instance they are not available on OS/X – RobM Jul 19 '13 at 21:10
  • 1
    osx `man tcp` contains an option `TCP_KEEPALIVE` that accepts seconds between probes, that is equivalent to `TCP_KEEPINTVL` in linux. option is not exported in Python 2.7 or 3.3, but I think it's possible to use the correct integer value `0x10` as key. – Dima Tisnek Nov 25 '13 at 20:05
  • 1
    @DimaTisnek TCP_KEEPINTVL looks equivalent, but how did you get that value `0x10`? – Alex Choi Jan 05 '18 at 16:33
  • Darwin `tcp.h`: https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/netinet/tcp.h – Dima Tisnek Jan 10 '18 at 07:04
  • Any ideas for Solaris - '_socketobject' object has no attribute 'IPPROTO_TCP', no SOL_SOCKET either – Kingsley Sep 12 '19 at 03:48
15

For windows, in python:

This will enable socket keep alive, with a 10 second keep alive time and a 3 second keep alive interval.

sock.ioctl(socket.SIO_KEEPALIVE_VALS, (1, 10000, 3000))
Didier Sampaolo
  • 2,566
  • 4
  • 24
  • 34
Ayy
  • 478
  • 3
  • 11
0

I have combined the above answers and made a single-function version for Linux, Darwin, and Windows.

https://pypi.org/project/keepalive-socket/

pip install keepalive-socket
import socket, keepalive

# keepalive.set(socket, after_idle_sec=60, interval_sec=60, max_fails=5)

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
keepalive.set(client_socket)
Orwellophile
  • 13,235
  • 3
  • 69
  • 45