Python socket programming - exception handling - python

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?

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.

Related

detect socket timeout when using "with" instead of "try"

Using python 3.6.8, I have the following code
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(20)
s.connect(host, port)
As I understand it, using with as shown instead of a try except block better handles the error condition that occurs if opening the socket (s.connect()) fails. How so? In the code as shown, if s.connect() times out, will it print a message? My main question is, can I detect that it timed out, e.g. to run some code if a timeout occurs? I want to be able to do that from within the with block without using try. I read this example
with opened_w_error("/etc/passwd", "a") as (f, err):
if err:
print "IOError:", err
else:
f.write("guido::0:0::/:/bin/sh\n")
But that doesn't detect the type of error. I read this as well
try:
with ContextManager():
BLOCK
except InitError: # raised from __init__
...
except AcquireResourceError: # raised from __enter__
...
except ValueError: # raised from BLOCK
...
except ReleaseResourceError: # raised from __exit__
But I'm hoping there is a way to detect if it's a timeout error from within the with block.

How to properly handle socket exception

In my Python program I have a socket listening to incoming connections and when I run nmap on it, it closes abruptly as it resets the connection when scanning the port.
I tried putting an except: pass block on the end of my code, along with the following:
if __name__ == "__main__":
try:
listen()
except KeyboardInterrupt:
pass
But upon receiving the connection reset, it doesn't pass. It just closes the program without printing anything.
How might I solve this?
The server-side code responsible for receiving and next to it, the handling of info. Should I put something after the while block, or just an except?
connection.listen(10)
while True:
current_connection, address = connection.accept()
current_connection.send('Input:')
while True:
data = current_connection.recv(2048)
The error:
Traceback (most recent call last):
File "server.py", line 41, in <module>
listen()
File "server.py", line 12, in listen
current_connection.send('Input:')
socket.error: [Errno 104] Connection reset by peer
The way your code is structured, if you put an except: pass at the top-level, then when the exception occurs, it's only trapped at the top level and there's nothing in your code to cause it go back into your listen..accept code. You should instead trap the exception at the right spot in the code so that your code continues the outer while True loop.
In general. it's a good idea to place all socket operations that might ordinarily fail inside a try-except block. It's considered bad practice in python to have a bare except though -- as a bare except tends to hide errors in your code that should not be hidden. Hence, you'll typically do something like this:
connection.listen(10)
while True:
current_connection, address = connection.accept()
try:
current_connection.sendall('Input:')
while True:
data = current_connection.recv(2048)
if data == '':
break # End of file (peer socket was closed)
except socket.error as sockerr:
print("Socket exception on send/recv", sockerr)
current_connection.close()
Also, note that I replaced send with sendall. This ensures that the entire string will get sent. (With send, it's valid in some circumstances for fewer bytes to be sent than the entire string.)

Treat try and except the same

I'm writing something that checks if a port is open, but modifying it to my use.
I set timeout for the check and if timeout reaches it raises socket.timeout exception, but I want a code block inside the try to also be invoked on socket.timeout:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
result = sock.connect_ex((check_server_ip, check_port))
if result == 0:
# act on open port
else:
# act on closed port
sock.close()
except socket.timeout:
# act on closed port
The code block I have on # act on closed port is long. I can create a function that has the code and call it on the else statement and socket.timeout exception, but I bet python has something more clever.
What can achieve this?
I don't think you need something clever or magical here. I looked at your code, then entered python -c "import this" in my terminal and saw this among the lines:
Flat is better than nested.
So, you don't need to create, set timeout and close a socket in the try ... except timeout - nothing throws timeout there:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
try:
result = sock.connect_ex((check_server_ip, check_port))
socket_connected = result == 0
except socket.timeout:
socket_connected = False
if socket_connected:
do_connected_stuff()
else:
do_disconnected_stuff()
sock.close()
However, the correctness of this code really depends on if do_connected_stuff() can throw socket.timeout and if do_disconnected_stuff() is a meaningful action in this case. If yes to all questions, then you've already got a pretty much optimal structure - at least without the full view of your system.

Create Socket Errors on Purpose / Python Script

I want to create socket errors (By doing things, obviously) but I've no idea how I should test if my script handles errors properly (If it dectes them.)
Currently, my code is this:
except socket.error as err:
print "Connection lost, waiting..."
time.sleep(5)
In theory, it should handle all the socket errors, print and then sleep (It's a part of a while loop.).
Any idea of how can I test it to see how it handles errors?
Use the raise statement:
try:
raise socket.error
except socket.error as err:
print "Connection lost, waiting..."
time.sleep(5)
Yet another example:
try:
raise AttributeError
except AttributeError:
print 'Sorry'
#Sorry
Also take a look at here and here

How do you maintain continous client / server communication?

I am trying to have a client connect to my server, and have a stream of communication between them. The only reason the connection should break is due to network errors, or unless the client wants to stop talking.
The issue I am running into is keeping the handler in a tight loop, and parsing the JSON.
My server code is :
#!/usr/bin/env python
import SocketServer
import socket
import json
import time
class MyTCPServer(SocketServer.ThreadingTCPServer):
allow_reuse_address = True
class MyTCPServerHandler(SocketServer.BaseRequestHandler):
def handle(self):
while 1:
try:
networkData = (self.request.recv(1024).strip())
try:
jsonInputData = json.loads(networkData)
print jsonInputData
try:
if jsonInputData['type'] == 'SAY_HI':
print "HI"
except Exception, e:
print "no hi"
pass
try:
if jsonInputData['type'] == 'GO_AWAY':
print "Going away!"
except Exception, e:
print "no go away"
pass
except Exception, e:
pass
#time.sleep(0.001)
#print "JSON Error", e
except Exception, e:
#time.sleep(0.001)
pass
#print "No message", e
server = MyTCPServer(('192.168.1.115', 13373), MyTCPServerHandler)
server.serve_forever()
My client code is simple :
#!/usr/bin/env python
import socket
import json
import time
import sys
hostname = '192.168.1.103'
port = 13373
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((hostname,port))
except Exception, e:
print "Error, could not open socket: ", e
data = {'type':'SAY_HI'}
sock.send(json.dumps(data))
data = {'type':'SAY_BYE'}
sock.send(json.dumps(data))
Sometimes I'll see the messages being sent, "SAY_HI" and "SAY_BYE", but most of the times, no data is being displayed on the server side.
This question is really not clear, but calling self.request.recv(1024) is very likely not what you want to do. You're eliminating all of the nice application-level handling that TCP will happily do for you. If you change that to self.request.recv(8) or a similarly very small number (such that recv() returns whenever it receives data, and doesn't try to fill your buffer), you may get better results.
Ultimately this is super-simplistic change, even if it works, that will not work in a larger context. You will need to be handling exceptions from your json parser on the server side and waiting for more data until an entire well-formed message is received.
This is a hopelessly more complex subject than will be handled generally in any SO answer. If you're going to be doing any amount of raw sockets programming, you absolutely must own a copy of Unix Network Programming, Volume 1.

Categories