21

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

Neuron
  • 5,141
  • 5
  • 38
  • 59
erling
  • 411
  • 2
  • 5
  • 14
  • how do you start your program? you sure your print is not going into /dev/null or something? also some exception inherit from BaseException so if you're really desperate you can try to catch that as well (this includes sys.exit and keyboard interrupt) – user3012759 Aug 22 '14 at 13:31

2 Answers2

25

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.

mhawke
  • 84,695
  • 9
  • 117
  • 138
  • 1
    Thanks bro! This was the problem, I terminated the program manually instead of waiting for the timeout. – erling Aug 22 '14 at 14:04
  • So if the timeout is set to `None`, you say there will still be a timeout exception after 120 seconds (or another default)? How can I get/set this default? – Itamar Katz Sep 08 '16 at 08:36
  • 1
    @ItamarKatz: that timeout is system defined. In Linux (and other Unix variants) it is indirectly controlled by the number of retries made to establish the connection - effectively the number of attempts to get a response to the SYN packet. You can see the setting with `cat /proc/sys/net/ipv4/tcp_syn_retries`. You can also change it by modifying that special file. The retires are usually sent using an exponential backoff algorithm which increases the interval between retries, e.g. 3 , 7 , 15, 31 secs. My Linux system has `tcp_syn_retries` set to 5 which works out to be approx 120 seconds. – mhawke Sep 08 '16 at 11:13
  • 1
    @ItamarKatz: Changing that setting affects all processes on your system, so I would advise against it. If you want to set a timeout do it with `socket.settimeout()`. If you want a timeout greater than that permitted by your OS you would need to handle that by performing your own retries in Python. – mhawke Sep 08 '16 at 11:19
  • Thanks a lot. Actually I am trying to do the opposite of limiting using timeout - my server script throws that `[Errno 110] Connection timed out` exception, and I don't understand why, that is I would like it to wait 'forever'. I am using `select` and only then reads using `socket.recv`, that's why I don't understand why this exception occurs. – Itamar Katz Sep 08 '16 at 12:53
  • @ItamarKatz: The stuff that I mention about the system timeout applies to connection establishment only, not to other I/O on the socket. With respect to connection establishment, you can not escape the system imposed timeout although you can retry the `connect()` in your Python code. Errno 110 refers to connection establishment, not to `recv()` nor `select()`. – mhawke Sep 08 '16 at 13:31
  • If i just write `Exception` in place of `socket.error` will the except clause will catch any type of exception? – y_159 Sep 27 '20 at 12:58
  • @y_159: yes, it will catch any `Exception` object, or any subclass of `Exception` which `socket.error` is. – mhawke Dec 31 '20 at 05:52
9

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
  • 2
    Thanks for your input, but after changing the timeout I am now able to catch the exceptions even though im not using "as". The colon misplacement was a typo. – erling Aug 22 '14 at 14:04