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.
Related
(python)
So I have a basic connection that works fine as long as whatever I want to connect to is online. The code is turned into a standalone using pyinstaller. If whatever I want to connect to is offline, when the standalone program is run it gives me a "Failed to excecute script test" (test being name of the program). How can I make it so it continues trying to establish a connection until it succeeds? Here is what I attempted below.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
result = s.connect_ex((host,port))
if result == 0:
break
else:
sleep_for = random.randrange(1,10)
time.sleep( sleep_for )
pass
Func1()
Func2()
s.close()
The documentation for connect_ex says:
Like connect(address), return an error indicator instead of raising an exception for errors returned by the C-level connect() call (other problems, such as “host not found,” can still raise exceptions)
That means that you still need to catch exceptions in order to infinitely retry to connect. In order to not make double work: processing connect_ex return value and catching exceptions, you can switch from using connect_ex to connect method and rewrite your code like this:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
s.connect((host,port))
break
except socket.error:
sleep_for = random.randrange(1,10)
time.sleep( sleep_for )
pass
Func1()
Func2()
s.close()
Using pyBluez, I use the following code to advertise and listen for a bluetooth connection:
def connect_socket():
global client_sock
try:
server_sock = BluetoothSocket(RFCOMM)
server_sock.bind(("", PORT_ANY))
server_sock.listen(1)
port = server_sock.getsockname()[1]
uuid = "00001101-0000-1000-8000-00805F9B34FB"
advertise_service(server_sock, "GSA",
service_id=uuid,
service_classes=[uuid, SERIAL_PORT_CLASS],
profiles=[SERIAL_PORT_PROFILE])
print("Waiting for connection on RFCOMM channel %d" % port)
client_sock, client_info = server_sock.accept()
print("Accepted connection from ", client_info)
except Exception as e: (yes, I know I'm catching all exceptions)
print(e)
I use the following to call the above and send data out from the socket. (I wind up waiting for a connection on every possible channel, which is not desirable, but that's not my only problem or the one that's prompting this question, though I'd like to fix it, too.)
def write_bt(message):
global client_sock
if client_sock is None:
threading.Thread(target=connect_socket).start()
if client_sock is not None:
try:
client_sock.send(message)
except Exception as e:
gsa_msg.message(e)
client_sock = None
I also need to receive data from the socket and write it to a usb connection. For this, I use the following:
def forward_bt_to_usb():
global client_sock
global serUSB
if (client_sock is not None) and (serUSB is not None):
try:
data = client_sock.recv(1024)
serUSB.write(data)
except Exception as e:
gsa_msg.error(e)
client_sock = None
Both write_bt() and forward_bt_to_usb() get called continuously from a loop and are communicating with the same client, but there isn't always data being received over the socket, and forward_bt_to_usb() seems to block everything in that case.
I believe that I probably have all of this structured improperly for what I'm trying to do, or perhaps I just need to have separate threads for sending and receiving data, but it's not obvious to me how to do that (Initially I just put some of the code from forward_bt_to_usb() in a separate thread, without realizing that that would just keep creating new threads as forward_bt_to_usb() kept getting called.)
It seems that what I'm trying to do should be pretty straightforward and certainly not novel, but I haven't been able to find examples or an explanation that I've been able to implement.
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.
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.
This question will expand on: Best way to open a socket in Python
When opening a socket how can I test to see if it has been established, and that it did not timeout, or generally fail.
Edit:
I tried this:
try:
s.connect((address, '80'))
except:
alert('failed' + address, 'down')
but the alert function is called even when that connection should have worked.
It seems that you catch not the exception you wanna catch out there :)
if the s is a socket.socket() object, then the right way to call .connect would be:
import socket
s = socket.socket()
address = '127.0.0.1'
port = 80 # port number is a number, not string
try:
s.connect((address, port))
# originally, it was
# except Exception, e:
# but this syntax is not supported anymore.
except Exception as e:
print("something's wrong with %s:%d. Exception is %s" % (address, port, e))
finally:
s.close()
Always try to see what kind of exception is what you're catching in a try-except loop.
You can check what types of exceptions in a socket module represent what kind of errors (timeout, unable to resolve address, etc) and make separate except statement for each one of them - this way you'll be able to react differently for different kind of problems.
You can use the function connect_ex. It doesn't throw an exception. Instead of that, returns a C style integer value (referred to as errno in C):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = s.connect_ex((host, port))
s.close()
if result:
print "problem with socket!"
else:
print "everything it's ok!"
You should really post:
The complete source code of your example
The actual result of it, not a summary
Here is my code, which works:
import socket, sys
def alert(msg):
print >>sys.stderr, msg
sys.exit(1)
(family, socktype, proto, garbage, address) = \
socket.getaddrinfo("::1", "http")[0] # Use only the first tuple
s = socket.socket(family, socktype, proto)
try:
s.connect(address)
except Exception, e:
alert("Something's wrong with %s. Exception type is %s" % (address, e))
When the server listens, I get nothing (this is normal), when it
doesn't, I get the expected message:
Something's wrong with ('::1', 80, 0, 0). Exception type is (111, 'Connection refused')
12 years later for anyone having similar problems.
try:
s.connect((address, '80'))
except:
alert('failed' + address, 'down')
doesn't work because the port '80' is a string. Your port needs to be int.
try:
s.connect((address, 80))
This should work.
Not sure why even the best answer didnt see this.