Rok Dolinar
Rok Dolinar

Reputation: 1006

Python socket programming - exception handling

I'm working on a basic socket client program in python and I'm not totally sure how to handle exceptions. This is what I did up to now:

TCP_IP      = '..............'
TCP_PORT    = 4950
MESSAGE     = "o3"
BUFFER_SIZE = 2048
data        = ""

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.settimeout(5.0)

try:
    s.connect((TCP_IP, TCP_PORT))
except socket.error:
    #write error code to file
    s.close()

try:
    s.sendall(MESSAGE)
except socket.error:
    #write to file or whatever
    s.close()

try:
    data = s.recv(BUFFER_SIZE)
except socket.error:
    #write to file or whatever
    s.close()

finally:
    s.close()

The code is working as I want, but I'm not sure if I should nest try/catch blocks or not? Should I put socket.socket into try/catch block too?

Second question, what will s.settimeout() do in my case? As far as I understood the documentation, it will throw an exception after 5 seconds, but for what? Just connect or will it do the same for sendall and recv?

Upvotes: 2

Views: 34719

Answers (1)

aneroid
aneroid

Reputation: 16137

Since you're doing exactly the same actions in all the exception blocks and catching the same socket.error exception, you could put s.connect, s.sendall and s.recv in the same try: block. Like so:

try:
    s.connect((TCP_IP, TCP_PORT))
    s.sendall(MESSAGE)
    data = s.recv(BUFFER_SIZE)
except socket.error:
    #write error code to file
finally:
    s.close()

Note that since s.close is also in the finally section in your example, it will always get called, even after an exception has occurred. So you'd end up with another exception occurring when you try to close an already closed socket. By not putting it in the except block and only in finally, you can avoid that situation.

If you do intend to handle each error in a different way, then you can leave them separate as you already have. But make sure to break/return at the end of the exception block so that you don't try the next. It's done that way in the socket examples, by using a continue in the loop.

Nesting them would help if you wanted to do something different in the exception block. But if not you'd be repeating the except block every time. And if you wanted to do something different, when you exit the nested-trys, you wouldn't be certain of which level it has completed or raised an exception - would need to use flag values etc. to merely track that. So for your example of the same error handling code, at the very least, do something like this in your except block:

except socket.error as e:
    socket_error_handler(e, s)

def socket_error_handler(exception, socket):
    #write error code to file
    etc.

Should I put socket.socket into try/catch block too?

They do that in the examples, linked above.

Apart from logging, you shouldn't really be doing the same exception handling at each stage. Probably need to handle those separately.

Part 2:

s.settimeout(5.0) sets the timeout for each socket operation, not just the first connect. Also implies that it's in blocking mode.

Upvotes: 5

Related Questions