python / cpython

The Python programming language
https://www.python.org
Other
63.41k stars 30.37k forks source link

Add TCP keepalive option for `asyncio.start_server()` #101336

Closed beavailable closed 11 months ago

beavailable commented 1 year ago

By default, this asyncio.start_server() method will create a list of socket objects usually for both IPv4 and IPv6 (if possible) and do not set keepalive option. if I want I can create a socket object by myself and set keepalive option for it, then pass it in start_server(), but if so, I will not be able to start a server which listens on both IPv4 and IPv6 addresses. I hope we can add a keepalive parameter for asyncio.start_server() or do something else to make things easier.

Linked PRs

axoroll7 commented 1 year ago

I don't have the same problem as you, but I understand your problem. It is a recurrent problem for me. For many projects, not only web servers, but others TCP servers too. The same problem appears with others programming languages. To alleviate this problem in Python, I thought about monkey-patching the library in question, or the socket library to use TCP keepalive. The mode being applied before bind and connect. Can TCP keepalive be applied after bind, connect or the first interaction ? In addition to this, it is difficult to access the internal sockets.

For some software prototypes, (never in production), I patched some methods of the socket object to add TCP keepalive, for most OSes :

Function signature :

def tcp_keepalive(
        sock:socket.socket,
        idle:int,
        interval:int,
        max:Optional[None] = None,
    ) -> None:
    pass

For linux :

sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, idle)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval)
if max is not None:
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max)

For BSD (macOS, FreeBSD, OpenBSD, NetBSD) :

# BSD offers only one parameter
TCP_KEEPALIVE = 0x10
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, TCP_KEEPALIVE, idle)

For Windows :

# max is not configurable on Windows
sock.ioctl(socket.SIO_KEEPALIVE_VALS, (1, idle * 1000, interval * 1000))

(English isn't my first language, so please excuse any mistakes.)

beavailable commented 1 year ago

Can TCP keepalive be applied after bind, connect or the first interaction ?

Seems that it can't.

gvanrossum commented 11 months ago

Please just propose a pull request that adds a keyword parameter to the right API. We will take it from there.