I'm working on a Python script with a client/server socket. After searching for alternate solutions, I'm not sure if my solution is correct or the best.
I have read these posts :
Python handling socket.error: [Errno 104] Connection reset by peer
Asyncio detecting disconnect hangs
Their solutions do not work for me, but I have the following .I'm not sure if that it's correct or clean.
try:
# See if client has disconnected.
try:
data = (await asyncio.wait_for(client_reader.readline(),timeout=0.01))
except ConnectionResetError, ConnectionAbortedError) as e:
break # Client disconnected
except TimeoutError:
pass # Client hasn't disconnect
If i don't use except for ConnectionResetError, I get an error because the data raises connectionReset when I kill the client.
Is it a good solution to detect an irregular client disconnection ?
ps : Thank you Prune for cleaned up wording and grammar.
As long as you are not interacting with the socket, you don't know if it's still connected or not. The proper way to handle disconnections is not to checks the state of the socket, but to verify if a read or write operation failed because of such error.
Usually, one is always at least awaiting for a read() on a socket, this is where one should look for disconnections. When the exception happens, the stream will be detected as closed and propagate the exception to any other task awaiting on an operation on this socket. It means that if you have concurrent operations on one stream, you must expect this exception to be raised anywhere, and handle it everywhere in your code.
About the exceptions caught: Checking for a ConnectionError is the best solution, it's a parent class of all exceptions related to a connection (ConnectionAbortedError, ConnectionResetError, etc).
Related
I'm using django-channels. When an exception is raised within a consumer it will log the error, the websocket connection will be disconnected and then it will re-connect again.
I would like to send a websocket message before it disconnects. I've tried to catch the error, send the message and then re-raise the exception. But the message still isn't sent.
What's the best way of achieving this?
When you raise an error it seems like the the actual raising of the error takes precedence of sending the message which happens later.
So the solution I went with in the end was to catch the exception in place, append the exception and check whether there were any exceptions to be raised after a message was sent.
If there was an error to raise, raise it. That way errors are raised server side and any errors will get known frontend side as well.
Alternatively, which might be a better solution. Catch the error and then log the exception. Have a special method that sends the error back to frontend and then return early.
That way the server will never disconnect and there is no need for re-connection. Which saves some time and processing.
I have a server that is connected to a socket on a cellphone. I check if the connection is open by assigning the socket.recv() command to a variable and checking its length. If its length is 0 then I close the connection. Also if I receive any exception other than a socket.timeout exception I also close the socket (short example below). This works well except for one situation. When the phone which is the client changes from a wifi to a GSM network or visa versa, data stops being sent and received. However, the sockets on the and the cell phone server do not throw an exception, nor does it give a 0 length string to indicate the socket is done writing. They just continue as if nothing has happened.
The sockets persist until I manually close them. Right now I'm doing this with a received data timeout, ie if I haven't received data in 2 minutes or more reset the connection. However, I am wondering if there is another way to catch or prevent this from happening. Is there a way to preserve a socket even when your network changes?
conn,addr=s.accept()
while True:
try:
message=conn.recv(1024)
while len(message) > 0:
#do something here
message=conn.recv(1024)
except socket.timeout:
pass
except:
conn.close()
how can I catch sendMessage error ? There is no exception propagation. When the server is down (half-open connection) I want catch the error in my client code. If the server running the websocket daemon crashes, reboots, loses network connectivity closeConnection/ConnectionLost/ConnectionFailed callbacks does not work.
from autobahn.websocket import WebSocketClientProtocol
class ClientProtocol(WebSocketClientProtocol):
def onOpen(self):
def heartbeat():
self.sendMessage("HB")
self.factory.reactor.callLater(1, heartbeat)
# I want to catch a socket error
try:
heartbeat()
except Exception as e:
print e
Maybe there are better solutions than this. Ping Pong ? Simply I cannot find a way how my client can detect server crash/reboots then reconnect.
I am using autobahn 0.6.5
Yes, there is a better solution for fast detection of lost connections: WebSocket ping/pong. This is built into the WebSocket protocol.
AutobahnPython supports automatic WebSocket Ping/Pong, mostly for exact this scenario (fast connection loss detection and connection keep-alive).
You can activate this using these parameters:
autoPingInterval
autoPingTimeout
autoPingSize
which can be set for both servers and clients.
You will need a recent AutobahnPython version (0.9.4+ I think). Yours (0.6.5) does not have that feature.
I'm using python socket to connect to a server but sometimes I get this:
error: [Errno 10060] A connection attempt failed because the connected
party did not properly respond after a period of time, or established
connection failed because connected host has failed to respond
when I call the socket.connect method
s= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((self._ipv4address, host_port))
try:
s.connect((dest_ip, dest_port))
except:
raise
Why am I seeing this error? And how do I solve the problem?
You don't need to bind the socket (unless the remote server has an expectation of incoming socket) - it is extremely rare that this would actually be a requirement to connect.
Instead of using sockets to open a website, use urllib2 or mechanize if you need to twiddle forms. They manage cookies, sessions, page state, etc.. Much easier.
Also, if you fail to to connect.. don't give up! Try again, some sites can be pokey to respond. Some may not respond for a while depending - handle it better. Instead of just raising the error, wrap your connection method with an exponential backoff decorator.
So far my networking code works fine, but I'm a bit worried about something I hid under the carpet:
The man pages for accept, close, connect, recv and send mention that errno.EINTR can show up when a system call was interrupted by a signal.
I am quite clueless here.
What does python do with that ? Does it automatically retry the call, does it raise a socket.error with that errno ? What is the appropriate thing I should do if that exception is raised ? Can I generate these signals myself in my unittests ?
Python simply retries the call and hides the signal from the user (helps with cross-platform consistency where -EINTR doesn't exist). You can safely ignore the EINTR issue but if you'd like to test it anyway, it's easy to do. Just set up a blocking operation that will not return (such as a socket.accept with no incoming connection) and send the process a signal.