I'm writing a Python program which uses the pyserial module. The program is designed to read the output from an Arduino module. I can open a serial object with:
ser = serial.Serial('/dev/cu.usbmodem641', 9600)
I can then read from it with:
line = ser.readline()
However, I want to be able to handle the exception that is thrown if I start the program without the Arduino module connected. The exception that is thrown is:
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/serial/serialposix.py", line 292, in open
raise SerialException(msg.errno, "could not open port %s: %s" % (self._port, msg))
If I try to catch this with a general try/except block in my main program, it isn't caught. I've tried importing the SerialException from serialposix.py but that doesn't work.
Do I need to get my hands dirty with threading or is there another way of dealing with this? When the exception is thrown, I'd like to call time.sleep(5) and then just retry until the connection is available.
You can import serial.SerialException and catch that:
from serial import SerialException
try:
line = ser.readline()
except SerialException:
time.sleep(5)
The exception is a subclass of IOError, so you could use that too, but then you may be catching exceptions thrown for reasons other than the port not yet being available.
Related
I cannot understand why sometimes I cannot catch the TimeOutError inside my flash_serial_buffer method.
When running my program I sometimes get a TimeOutError that is not caught and I cannot understand why. I indicate the code of the signal handlers and the methods where the TimeOutError is not caught. How could this be happening?
This is the code for my signal handler definition and callback function.
Basically if the time ends, the signal handler is called and raises a timeout error.
def signal_handler(signum, frame):
print "PUM"
raise TimedOutError("Time out Error")
signal.signal(signal.SIGALRM, signal_handler)
The flush serial buffer blocks if there is no answer to
answer = xbee.wait_read_frame()
The idea is to clean everything in the buffer until there aren’t any more messages. When there are no more messages, it just waits for the SIGALRM to explode and raises the timeout error.
def flush_serial_buffer(xbee):
# Flush coordinators serial buffer if problem happened before
logging.info(" Flashing serial buffer")
try:
signal.alarm(1) # Seconds
while True:
answer = xbee.wait_read_frame()
signal.alarm(1)
logging.error(" Mixed messages in buffer")
except TimedOutError:
signal.alarm(0) # Seconds
logging.error(" No more messages in buffer")
signal.alarm(0) # Supposedly it never leaves without using Except, but...
Is there a case where the TimeOutError might be raised, but not caught by the try: statement?
Here is my error class definition:
class TimedOutError(Exception):
pass
I was able to repeat the error again. I really cannot understand why the try does not catch the error it.
INFO:root: Flashing serial buffer
PUM
Traceback (most recent call last):
File "/home/ls/bin/pycharm-community-4.0.6/helpers/pydev/pydevd.py", line 1458, in trace_dispatch
if self._finishDebuggingSession and not self._terminationEventSent:
File "/home/ls/PiProjects/Deployeth/HW-RPI-API/devices.py", line 42, in signal_handler
raise TimedOutError("Time out Error")
TimedOutError: Time out Error
I would recommend in this case replacing the try and except code with this:
try:
signal.alarm(1) # Seconds
while True:
answer = xbee.wait_read_frame()
signal.alarm(1)
logging.error(" Mixed messages in buffer")
except:
signal.alarm(0) # Seconds
logging.error(" No more messages in buffer")
PS: You don't need to include try (whatever error) in your try and except statements.
Basically, I've read in several places that socket.recv() will return whatever it can read, or an empty string signalling that the other side has shut down (the official docs don't even mention what it returns when the connection is shut down... great!). This is all fine and dandy for blocking sockets, since we know that recv() only returns when there actually is something to receive, so when it returns an empty string, it MUST mean the other side has closed the connection, right?
Okay, fine, but what happens when my socket is non-blocking?? I have searched a bit (maybe not enough, who knows?) and can't figure out how to tell when the other side has closed the connection using a non-blocking socket. There seems to be no method or attribute that tells us this, and comparing the return value of recv() to the empty string seems absolutely useless... is it just me having this problem?
As a simple example, let's say my socket's timeout is set to 1.2342342 (whatever non-negative number you like here) seconds and I call socket.recv(1024), but the other side doesn't send anything during that 1.2342342 second period. The recv() call will return an empty string and I have no clue as to whether the connection is still standing or not...
In the case of a non blocking socket that has no data available, recv will throw the socket.error exception and the value of the exception will have the errno of either EAGAIN or EWOULDBLOCK. Example:
import sys
import socket
import fcntl, os
import errno
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK)
while True:
try:
msg = s.recv(4096)
except socket.error, e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
sleep(1)
print 'No data available'
continue
else:
# a "real" error occurred
print e
sys.exit(1)
else:
# got a message, do something :)
The situation is a little different in the case where you've enabled non-blocking behavior via a time out with socket.settimeout(n) or socket.setblocking(False). In this case a socket.error is stil raised, but in the case of a time out, the accompanying value of the exception is always a string set to 'timed out'. So, to handle this case you can do:
import sys
import socket
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
s.settimeout(2)
while True:
try:
msg = s.recv(4096)
except socket.timeout, e:
err = e.args[0]
# this next if/else is a bit redundant, but illustrates how the
# timeout exception is setup
if err == 'timed out':
sleep(1)
print 'recv timed out, retry later'
continue
else:
print e
sys.exit(1)
except socket.error, e:
# Something else happened, handle error, exit, etc.
print e
sys.exit(1)
else:
if len(msg) == 0:
print 'orderly shutdown on server end'
sys.exit(0)
else:
# got a message do something :)
As indicated in the comments, this is also a more portable solution since it doesn't depend on OS specific functionality to put the socket into non-blockng mode.
See recv(2) and python socket for more details.
It is simple: if recv() returns 0 bytes; you will not receive any more data on this connection. Ever. You still might be able to send.
It means that your non-blocking socket have to raise an exception (it might be system-dependent) if no data is available but the connection is still alive (the other end may send).
When you use recv in connection with select if the socket is ready to be read from but there is no data to read that means the client has closed the connection.
Here is some code that handles this, also note the exception that is thrown when recv is called a second time in the while loop. If there is nothing left to read this exception will be thrown it doesn't mean the client has closed the connection :
def listenToSockets(self):
while True:
changed_sockets = self.currentSockets
ready_to_read, ready_to_write, in_error = select.select(changed_sockets, [], [], 0.1)
for s in ready_to_read:
if s == self.serverSocket:
self.acceptNewConnection(s)
else:
self.readDataFromSocket(s)
And the function that receives the data :
def readDataFromSocket(self, socket):
data = ''
buffer = ''
try:
while True:
data = socket.recv(4096)
if not data:
break
buffer += data
except error, (errorCode,message):
# error 10035 is no data available, it is non-fatal
if errorCode != 10035:
print 'socket.error - ('+str(errorCode)+') ' + message
if data:
print 'received '+ buffer
else:
print 'disconnected'
Just to complete the existing answers, I'd suggest using select instead of nonblocking sockets. The point is that nonblocking sockets complicate stuff (except perhaps sending), so I'd say there is no reason to use them at all. If you regularly have the problem that your app is blocked waiting for IO, I would also consider doing the IO in a separate thread in the background.
I'm reading this script. It synchronizes files via FTP.
I'm confused with this statement in line 106
try:
...
except error_perm, msg:
...
It seems the variables error_perm and msg come from nowhere. When the try part goes wrong, the script halts and fails to go into the except part.
You have the next import on the top of the file:
from ftplib import FTP, error_perm
error_perm is an error class.
statement
except error_perm, msg:
catches any exception with type error_perm and stores exception object in variable msg.
import is correct, exception handling is a bit different syntax for python 3.6 and up:
except error_perm as msg:
print(f"FTP error: {msg}",flush=True)
Hey I'm wondering how to handle specific error codes. For example, [Errno 111] Connection refused
I want to catch this specific error in the socket module and print something.
If you want to get the error code, this seems to do the trick;
import errno
try:
socket_connection()
except socket.error as error:
if error.errno == errno.ECONNREFUSED:
print(os.strerror(error.errno))
else:
raise
You can look up errno error codes.
On Unix platforms, at least, you can do the following.
import socket, errno
try:
# Do something...
except socket.error as e:
if e.errno == errno.ECONNREFUSED:
# Handle the exception...
else:
raise
Before Python 2.6, use e.args[ 0 ] instead of e.errno.
This seems hard to do reliably/portably but perhaps something like:
import socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 4167))
except socket.error, e:
if 'Connection refused' in e:
print '*** Connection refused ***'
which yields:
$ python socketexception.py
*** Connection refused ***
Pretty yucky though.
I'm developing on Windows and found myself in the same predicament. But the error message always contains the error number. Using that information I just convert the exception to a string str(Exception), convert the error code I wanna check for to a string str(socket.errno.ERRORX) and check if the error code is in the exception.
Example for a connection reset exception:
except Exception as errorMessage:
if str(socket.errno.ECONNRESET) in str(errorMessage):
print("Connection reset")
#etc...
This avoids locale specific solutions but is still not platform independent unfortunately.
I have a try/except block that sends a message and waits for confirmation from client. If the client terminates, pickle raises an EOFError, but the code below does not catch the error and execute the graceful shut down. It instead prints stack trace. I assume it has to do with the line "except socket.error, EOFError:" - am I using the wrong syntax to handle both socket.error and EOFError there?
try:
msgs = [1]
self.sock.send(pickle.dumps(msgs))
rdy = pickle.loads(self.sock.recv(2097152))
except socket.error, EOFError:
print 'log socketmanager closing'
self.terminate()
break
In Python 2.x, the form except a, b catches an exception of type a and assign it to a variable called b. In your case this would result in EOFError being ignored. Try this instead:
...
except (socket.error, EOFError):
...
Edit: to elaborate, the new syntax in Python 3.0, and available, though not required, in 2.6+, for capturing the value of an exception is except a as b.
break is causing the error, it can only be used inside a for loop or a try/finally block, not try/except, see docs and more.