Python script hangs in loop
In one of my scripts I'm using the following infinite loop to check for an active internet connection:
def online_check():
try:
con = urllib2.urlopen("http://www.google.com/")
data = con.read()
logging.debug('{0} Reached the host. Exiting online_check'.format(time.开发者_高级运维strftime('[ %H:%M:%S ]')))
except:
logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
time.sleep(3)
online_check()
I am aware that this is not a very elegant solution but the problem is that when I start my script it will sometimes call the online_check method and get stuck in the middle of it (Once in roughly 200 attempts). The script is still running and no exception is thrown; the script is just stuck. I can press CTRL+C (Even after hours of the script being stuck) and it will just throw an exception and continue with the next online_check. I also rewrote the script to check for an IP address in 'ifconfig' as opposed to pinging google, unfortunately with similar results.
What am I doing wrong? Can I rewrite the script so this never happens? Is there something I can do to find out what is happening here?
Help is greatly appreciated. Btw. I'm using Python2.7.1 and I've tried this script both on Linux and Mac.
P.S: If you have recommendations for designing a method that checks for connectivity without using bandwidth and minimal overhead, I'd be more than happy to hear it.
You are running into infinite recursion, a method you can do to not have this happen is pass an argument into online_check for the maximum check.
Such as:
def online_check(max_checks=10, current_check=0):
try:
con = urllib2.urlopen("http://www.google.com/")
data = con.read()
logging.debug('{0} Reached the host. Exiting online_check'.format(time.strftime('[ %H:%M:%S ]')))
except:
logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
if max_checks > current_check:
time.sleep(3)
online_check(max_checks, current_check+1)
So you would do:
online_check(5) # for 5 maximum checks
online_check() # use the default value, which is 10
I also suggest you catch more specific exceptions, for better coding habits but also because when you do CTRL-C, Python throws a KeyboardInterrupt exception, which your code actually catches because you catch all exceptions.
In addition to the infinite recursion (CPython as far as I'm aware doesn't support optimized tail-end recursion), you are not closing your connection.
You might be hitting some kind of connection limit either with the OS or with Google when it retries. This probably happens before reaching max recursion depth which is why you don't get an exception.
The connection would normally close when it get garbage collected, but I think because of the recursion the variable doesn't completely go out of scope until the recursion ends.
Also as @senderle mentioned, you should try to catch a more specific error.
Try:
def online_check():
while True:
try:
con = urllib2.urlopen("http://www.google.com/")
data = con.read()
logging.debug('{0} Reached the host. Exiting online_check'.format(time.strftime('[ %H:%M:%S ]')))
except urllib2.URLError:
logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
time.sleep(3)
finally:
con.close()
(Warning untested code)
In addition to others' suggestions, you should really specify which exception(s) you're catching. Control-C doesn't work because that just raises an exception, and your except
statement interprets it as being the same as all others.
Seems like the exception you want is urllib2.URLError
.
At some point this program is going to end up encountering the recursion depth limit for your interpreter. Typically, a function that should continuously run would be structured like so:
def online_check():
while True:
try:
con = urllib2.urlopen("http://www.google.com/")
data = con.read()
logging.debug('{0} Reached the host. Exiting online_check'.format(time.strftime('[ %H:%M:%S ]')))
break
except:
logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
time.sleep(3)
That should give you better results. I imagine you've already got a separate thread that's running this function (otherwise later code can't execute - this function never returns).
精彩评论