Issue using select() and TCP Keepalive with Python sockets
As the comments to your question have mentioned, the TCP_KEEPALIVE
stuff won't make any difference for your use-case. TCP_KEEPALIVE
is a mechanism for notifying a program when the peer on the other side of its TCP connection has gone away on an otherwise idle TCP connection. Since you are regularly sending data on the TCP connection(s), the TCP_KEEPALIVE
functionality is never invoked (or needed) because the act of sending data over the connection is already enough, by itself, to cause the TCP stack to recognize ASAP when the remote client has gone away.
That said, I modified/simplified your example server code to get it to work (as correctly as possible) on my machine (a Mac, FWIW). What I did was:
Moved the
socket.setsockopt(SO_REUSEADDR)
to before thebind()
line, so thatbind()
won't fail after you kill and then restart the program.Changed the
select()
call to watch for writable-sockets.Added exception-handling around the
send()
calls.Moved the remove-socket-from-lists code into a separate
RemoveSocketFromLists()
function, to avoid redundant code
If, on the other hand, the client's network connectivity is disconnected suddenly (e.g. because someone yanked out the client computer's Ethernet or power cable) then it may take the server program several minutes to detect that the client has gone away, and that's expected behavior, since there's no way for the server to tell (in this situation) whether the client is dead or not. (i.e. it doesn't want to kill a viable TCP connection simply because a router dropped a few TCP packets, causing a temporary interruption in communications to a still-alive client)
If you want to try to drop the clients quickly in that scenario, you could try requiring the clients to send()
a bit of dummy-data to the server every second or so. The server could keep track of the timestamp of when it last received any data from each client, and force-close any clients that it hasn't received any data from in "too long" (for whatever your idea of too long is). This would more or less work, although it risks false-positives (i.e. dropping clients that are still alive, just slow or suffering from packet-loss) if you set your timeout-threshold too low.
#!/usr/bin/env python3
import select, socket
# Listen Port
LISTEN_PORT = 1234
# Create socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Make socket reusable
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Setup the socket
server.setblocking(0)
server.bind(('0.0.0.0', LISTEN_PORT))
server.listen(5)
# Tell user we are listening
print("Listening on port %s" % LISTEN_PORT)
inputs = [server]
outputs = []
# Removes the specified socket from every list in the list-of-lists
def RemoveSocketFromLists(s, listOfLists):
for nextList in listOfLists:
if s in nextList:
nextList.remove(s)
while True:
# Detecting clients that disappeared does NOT work when we ARE
# watching if any sockets are writable
readable, writable, exceptional = select.select(inputs, outputs, [])
for s in readable:
if s is server:
connection, client_address = s.accept()
print("New client connected: %s" % (client_address,))
connection.setblocking(0)
inputs.append(connection)
outputs.append(connection)
else:
try:
data = s.recv(1024)
print("Data from %s: %s" % (s.getpeername(), data.decode('ascii').rstrip()))
except:
print("recv() reports that %s disconnected" % s)
RemoveSocketFromLists(s, [inputs, outputs, writable])
for s in writable:
try:
numBytesSent = s.send(b".")
except:
print("send() reports that %s disconnected" % s)
RemoveSocketFromLists(s, [inputs, outputs])
Python Sockets - Keeping a connection to a server alive from the client
For enabling keep alive there is a duplicate question at How to change tcp keepalive timer using python script?
Keep in mind some servers and intermediate proxies forcibly close long lived connections regardless of keep alives being used or not, in which case you will see a FIN,ACK after X amount of time no matter what.
robust continuous TCP connection (python socket)
I will try to answer both questions.
... Is there some way that the socket sends an interrupt for a connection that is dead ...
I know none. TCP_KEEPALIVE only tries to maintain the connection. It is very useful if any equipment on the network flow has a timeout, because it prevents the timeout to abort the connection. But if the connection drops because because of any other reason (that timeout) TCP_KEEPALIVE cannot do anything. The rationale is that there is no need to restore a dropped inactive connection before something has to be exchanged.
Is this a robust way of handling a continous TCP connection?
Not really.
The robust way is to be prepared that the connection fails for any reason at any moment. So you should be prepared to face an error when sending a message (your code is) and if that happens try to re-open the connection and send the message again (your current code does not). Something like:
def connect(...):
# establish and return a connection
...
return clientSocket
clientSocket = connect(...)
while True:
...
while True:
try:
clientSocket.send(message)
break
except OSError:
clientSocket = connect()
...
shutdown
) should not immediately close the socket, but start a read loop and only close when everything has be received and processed. python requests keep connection alive for indefinite time
By using requests.Session
, keep-alive is handled for you automatically.
In the first version of your loop that continuously polls the server after the /auth
call is made, the server does not drop the connection due to the subsequent GET
that happens. In the second version, it's likely that sleep interval exceeds the amount of time the server is configured to keep the connection open.
Depending on the server configuration of the API, the response headers may include a Keep-Alive
header with information about how long connections are kept open at a minimum. HTTP/1.0
specifies this information is included in the timeout
parameter of the Keep-Alive
header. You could use this information to determine how long you have until the server will drop the connection.
In HTTP/1.1
, persistent connections are used by default and the Keep-Alive
header is not used unless the server explicitly implements it for backwards compatibility. Due to this difference, there isn't an immediate way for a client to determine the exact timeout for connections since it may exist solely as server side configuration.
The key to keeping the connection open would be to continue polling at regular intervals. The interval you use must be less than the server's configured connection timeout.
One other thing to point out is that artificially extending the length of the session indefinitely this way makes one more vulnerable to session fixation attacks. You may want to consider adding logic that occasionally reestablishes the session to minimize risk of these types of attacks.
Is detecting a TCP socket disconnect in Python possible?
It is perfectly fine for TCP connections to not transfer any kind of data for a long time. And it is also not a problem if a cable gets disconnected as long as it is reconnected later data need to be transmitted.
The only way to be sure that the peer is still reachable is to have some kind of heartbeat. This can be either be done at the application level or it can be done at the TCP level - using TCP keep-alive. Usually systems offer a way to not only enable TCP keep-alive per socket but also to adjust how often a keep-alive packet will be send when the socket is idle, i.e. how quick an application can find out that the peer is no longer there. To get to the details on how to do this in Python see How to change tcp keepalive timer using python script?.
How to set keepalive option for induvidual socket in VxWorks
From the VxWorks "Library Reference" manual (can be download):
OPTIONS FOR STREAM SOCKETS
The following sections discuss the socket options available for stream (TCP) sockets.
SO_KEEPALIVE -- Detecting a Dead Connection
Specify the SO_KEEPALIVE option to make the transport protocol (TCP) initiate a timer to detect a dead connection:
setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof (optval));
This prevents an application from hanging on an invalid connection. The value at optval for this option is an integer (type int), either 1 (on) or 0 (off).The integrity of a connection is verified by transmitting zero-length TCP segments triggered by a timer, to force a response from a peer node. If the peer does not respond after repeated transmissions of the KEEPALIVE segments, the connection is dropped, all protocol data structures are reclaimed, and processes sleeping on the connection are awakened with an ETIMEDOUT error.
The ETIMEDOUT timeout can happen in two ways. If the connection is not yet established, the KEEPALIVE timer expires after idling for TCPTV_KEEP_INIT. If the connection is established, the KEEPALIVE timer starts up when there is no traffic for TCPTV_KEEP_IDLE. If no response is received from the peer after sending the KEEPALIVE segment TCPTV_KEEPCNT times with interval TCPTV_KEEPINTVL, TCP assumes that the connection is invalid. The parameters TCPTV_KEEP_INIT, TCPTV_KEEP_IDLE, TCPTV_KEEPCNT, and TCPTV_KEEPINTVL are defined in the file target/h/net/tcp_timer.h.
Related Topics
Plotting Results of Hierarchical Clustering Ontop of a Matrix of Data in Python
Change to Sudo User Within a Python Script
Is There a Numpy Builtin to Reject Outliers from a List
How to Get the Version Defined in Setup.Py (Setuptools) in My Package
Convert Date to Datetime in Python
How to Calculate the Inverse of the Normal Cumulative Distribution Function in Python
How to Tell Pycharm What Type a Parameter Is Expected to Be
Numpy Version of "Exponential Weighted Moving Average", Equivalent to Pandas.Ewm().Mean()
Django - Makemigrations - No Changes Detected
Possible Values from Sys.Platform
Installing Pygraphviz on Windows 10 64-Bit, Python 3.6
How to Save and Restore Multiple Variables in Python