I have a socket-connection going on and I wanna improve the exception handling and I'm stuck. Whenever I call socket.connect(server_address) with an invalid argument the program stops, but doesn't seem to raise an exception. Here is my code:
import socket
import sys
import struct
class ARToolkit():
def __init__(self):
self.x = 0
self.y = 0
self.z = 0
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.logging = False
def connect(self,server_address):
try:
self.sock.connect(server_address)
except socket.error, msg:
print "Couldnt connect with the socket-server: %s\n terminating program" % msg
sys.exit(1)
def initiate(self):
self.sock.send("start_logging")
def log(self):
self.logging = True
buf = self.sock.recv(6000)
if len(buf)>0:
nbuf = buf[len(buf)-12:len(buf)]
self.x, self.y, self.z = struct.unpack("<iii", nbuf)
def stop_logging(self):
print "Stopping logging"
self.logging = False
self.sock.close()
The class maybe looks a bit wierd but its used for receiving coordinates from another computer running ARToolKit. Anyway, the issue is at the function connect():
def connect(self,server_address):
try:
self.sock.connect(server_address)
except socket.error, msg:
print "Couldnt connect with the socket-server: %s\n terminating program" % msg
sys.exit(1)
If I call that function with a random IP-address and portnumber the whole program just stops up at the line:
self.sock.connect(server_address)
The documentation I've read states that in case of an error it will throw a socket.error-exception. I've also tried with just:
except Exception, msg:
This, if I'm not mistaken, will catch any exceptions, and still it yields no result. I would be very grateful for a helping hand. Also, is it okay to exit programs using sys.exit when an unwanted exception occurs?
Thank you
If you have chosen a random, but valid, IP address and port, socket.connect() will attempt to make a connection to that endpoint. By default, if no explicit timeout is set for the socket, it will block while doing so and eventually timeout, raising exception socket.error: [Errno 110] Connection timed out.
The default timeout on my machine is 120 seconds. Perhaps you are not waiting long enough for socket.connect() to return (or timeout)?
You can try reducing the timeout like this:
import socket
s = socket.socket()
s.settimeout(5) # 5 seconds
try:
s.connect(('123.123.123.123', 12345)) # "random" IP address and port
except socket.error, exc:
print "Caught exception socket.error : %s" % exc
Note that if a timeout is explicitly set for the socket, the exception will be socket.timeout which is derived from socket.error and will therefore be caught by the above except clause.
The problem with your last general exception is the colon placement. It needs to be after the entire exception, not after the except statement. Thus to capture all exceptions you would need to do:
except Exception,msg:
However from Python 2.6+ you should use the as statement instead of a comma like so:
except Exception as msg:
I was able to run the code fine (note you need to throw in a tuple to the connect method). If you want to specifically catch only socket errors then you would need to except the socket.error class. Like you have:
except socket.error as msg:
If you want to make sure that a tuple is entered simply add another exception loop:
except socket.error as msg:
print "Socket Error: %s" % msg
except TypeError as msg:
print "Type Error: %s" % msg
Related
sock1.settimeout(2)
conn.settimeout(1) #conn comes from sock1
except socket.timeout, e:
print <responsible socket>
Is there a way to distinguish the socket responsible for the timeout?
Perhaps I'm doing something wrong if I have two sockets that are timing out.
As far as I can tell, there's nothing in the socket.timeout exception object that identifies the socket. So you need to keep track of which socket you're reading from, that will be the one that timed out:
try:
cursock = sock1
data = sock1.recv(bufsize)
cursock = conn
data1 = conn.recv(bufsize)
except socket.timeout, e:
print cursock
Or you could wrap try/except around each recv call. You could put this into a helper function:
def try_recv(sock, bufsize, flags=0):
try:
return sock.recv(bufsize, flag)
except socket.timeout, e:
print sock
I am trying to handle a hard to duplicate error case using TCPServer. We have seen a few occurrences that when a socket timeout happens in the handler, the code never recovers and keeps returning the socket.timeout exception.
This looks to be from the following snippet in the Socket.py library code:
def readinto(self, b):
"""Read up to len(b) bytes into the writable buffer *b* and return
the number of bytes read. If the socket is non-blocking and no bytes
are available, None is returned.
If *b* is non-empty, a 0 return value indicates that the connection
was shutdown at the other end.
"""
self._checkClosed()
self._checkReadable()
if self._timeout_occurred:
raise OSError("cannot read from timed out object")
while True:
try:
return self._sock.recv_into(b)
except timeout:
self._timeout_occurred = True
raise
except InterruptedError:
continue
except error as e:
if e.args[0] in _blocking_errnos:
return None
raise
once a timeout has occurred _timeout_occurred is set to True, and the next pass into this function, the socket has the flag set, and will immediately exit with the cannot read from timed out object error.
Now the code uses TCP Server (only relevant code included) Basically it is reading stuff from the socket, and queing it to be handled separately.
def get_event(file_):
pre_package_len = 8
msg = file_.read(pre_package_len)
if len(msg) == pre_package_len:
pkg = PRE_PACKAGE_FRAME.unpack(msg)
msg = file_.read(pkg['len'])
logger.debug('recv: type: %s len: %s bytes read: %s',
pkg['type'], pkg['len'], len(msg))
if len(msg) >= pkg['len']:
if pkg['type'] == cdefs.kNotification:
e = EVENT_FRAME.unpack(msg)
return decode_event(e)
logger.warn('received unsupported package type: %s', pkg['type'])
else:
logger.error('failed to recv')
class _EventHandler(StreamRequestHandler):
def handle(self):
logger.debug("Got event from %s", self.client_address)
try:
e = get_event(self.rfile)
if e:
self.q.put(e)
except socket.timeout:
logger.error('timed out reading event')
def process_event(q, handler, shutdown_sentinel):
for e in iter(q.get, shutdown_sentinel):
try:
handler(e)
except Exception:
logger.exception('Unhandled exception handling event: %s', e)
logger.info('exiting')
def eventhandler_maker(q, timeout):
return type('NewEventHandler',
(_EventHandler, object),
dict(q=q, timeout=timeout))
def process_events(handler, address, timeout=20):
sentinel = object()
q = Queue()
eventhandler = eventhandler_maker(q, timeout)
server = TCPServer(address, eventhandler)
start_thread(server.serve_forever)
start_thread(process_event, (q, handler, sentinel))
def shutdown():
logger.info('shutting down')
q.put(sentinel)
server.shutdown()
def add_event(e):
q.put(e)
return shutdown, add_event
The symptoms are that once the timeout happens, the log keeps showing 'timed out reading event' and the code never does anything anymore. I added code to dump out the server.socket.gettimeout() and socket.getdefaulttimeout() and both return None. This application is running on an embedded Linux 3.10 kernel with python 3.4.0.
I have 2 questions here:
What is a good recovery strategy here? Shutdown() / Close() the server socket and then restart it? Or are there better strategies?
Is there a good third party tool to provoke a timeout so a recovery strategy can be proven to be correct?
I am writing a connector using UDP in Python 3.3
When I am sending data to the UDP port, everything works fine. The problem is that when I am not sending any data, I get an error generated by the receiving port once per minute that says "timed out". While debugging, I used the socket.gettimeout() function and it returned 'None'.
Why am I getting this timeout error? Any help would be greatly appreciated!
import socket
from EventArgs import EventArgs
import logging
class UDPServer(object):
"""description of class"""
def __init__(self, onMessageReceivedEvent = '\x00'):
self.__onMessageReceivedEvent = onMessageReceivedEvent
self.__s = '\x00'
self.__r = '\x00'
def openReceivePort(self,port):
try:
self.__r = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.__r.bind(("",port))
print ("opening port: ", port)
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
def openBroadcastPort(self):
try:
self.__s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.__s.bind(("",2101))
print ("opening port: ", 2101)
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
def closePorts():
if self.__r != '\x00':
self.__r.close()
if self.__s != '\x00':
self.__s.close()
def getUDPData(self):
try:
data, addr = self.__r.recvfrom(1024)
if self.__onMessageReceivedEvent != '\x00':
eventArgs = EventArgs()
eventArgs.Addr = addr
eventArgs.Data = data
self.__onMessageReceivedEvent.fire(self, eventArgs)
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
def send(self,ipAddress,port,message):
try:
self.__s.sendto(message.encode(),(ipAddress,23456))
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
I figured out the answer to my own problem. I was using the default configuration for socket.setblocking which is 0 (non-blocking). The documentation says that using this configuration is the equivalent of using a settimeout value of 0. If I use a blocking socket, it is the equivalent of using a settimeout value of 'None'. Once I changed to a blocking socket I no longer saw this error.
socket.setblocking(flag)-Set blocking or non-blocking mode of the socket: if flag is 0, the socket is set to non- blocking, else to blocking mode. Initially all sockets are in blocking mode. In non-blocking mode, if a recv() call doesn’t find any data, or if a send() call can’t immediately dispose of the data, a error exception is raised; in blocking mode, the calls block until they can proceed. s.setblocking(0) is equivalent to s.settimeout(0.0); s.setblocking(1) is equivalent to s.settimeout(None)*
Codes like this:
import socket, sys
try:
address = ('127.0.0.1', 31500)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(address)
except Exception:
errType, errValue, errTraceback = sys.exc_info()
# or
# handle the Exception it throw out ?
What I want to get is the errcode like 10060 which means connection time out, thanks for any help :)
Use
except EnvironmentError as e:
print e.errno
I understand the basic try: except: finally: syntax for pythons error handling. What I don't understand is how to find the proper error names to make readable code.
For example:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.settimeout(60)
char = s.recv(1)
except socket.timeout:
pass
so if socket raises a timeout, the error is caught. How about if I am looking for a connection refused. I know the error number is 10061. Where in the documentation do I look to find a meaning full name such as timeout. Would there be a similar place to look for other python modules? I know this is a newbie question but I have been putting in error handling my my code for some time now, without actually knowing where to look for error descriptions and names.
EDIT:
Thanks for all your responses.
would
except socket.error, exception:
if exception.errno == ETIMEDOUT:
pass
achieve the same result as
except socket.timeout:
pass
To achieve what you want, you'll have to grab the raised exception, extract the error code stored into, and make some if comparisons against errno codes:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.settimeout(60)
char = s.recv(1)
except socket.error, exception:
if exception.errno == errno.ECONNREFUSED:
# this is a connection refused
# or in a more pythonic way to handle many errors:
{
errno.ECONNREFUSED : manage_connection_refused,
errno.EHOSTDOWN : manage_host_down,
#all the errors you want to catch
}.get(exception.errno, default_behaviour)()
except socket.timeout:
pass
with :
def manage_connection_refused():
print "Connection refused"
def manage_host_down():
print "Host down"
def default_behaviour():
print "error"
You will get an error with an errno, which is described in the errno documentation. 10061 is only valid for WinSock.
According to socket, socket.error values are defined in the errno module.