Q:

Python socket error resilience / workaround

I have a script running that is testing a series of urls for availability.
This is one of the functions.
def checkUrl(url): # Only downloads headers, returns status code.
    p = urlparse(url)
    conn = httplib.HTTPConnection(p.netloc)
    conn.request('HEAD', p.path)
    resp = conn.getresponse()
    return resp.status

Occasionally, the VPS will lose connectivity, the entire script crashes when that occurs.
File "/usr/lib/python2.6/httplib.py", line 914, in request
  self._send_request(method, url, body, headers)
File "/usr/lib/python2.6/httplib.py", line 951, in _send_request
  self.endheaders()
File "/usr/lib/python2.6/httplib.py", line 908, in endheaders
  self._send_output()
File "/usr/lib/python2.6/httplib.py", line 780, in _send_output
  self.send(msg)
File "/usr/lib/python2.6/httplib.py", line 739, in send
  self.connect()
File "/usr/lib/python2.6/httplib.py", line 720, in connect
  self.timeout)
File "/usr/lib/python2.6/socket.py", line 561, in create_connection
  raise error, msg
socket.error: [Errno 101] Network is unreachable

I'm not at all familiar with handling errors like this in python.
What is the appropriate way to keep the script from crashing when network connectivity is temporarily lost?

Edit:
I ended up with this - feedback?
def checkUrl(url): # Only downloads headers, returns status code.
    try:
        p = urlparse(url)
        conn = httplib.HTTPConnection(p.netloc)
        conn.request('HEAD', p.path)
        resp = conn.getresponse()
        return resp.status
    except IOError, e:
        if e.errno == 101:
            print "Network Error"
            time.sleep(1)
            checkUrl(url)
        else:
            raise

I'm not sure I fully understand what raise does though..

A:

Problem with your solution as it stands is you're going to run out of stack space if there are too many errors on a single URL (> 1000 by default) due to the recursion. Also, the extra stack frames could make tracebacks hard to read (500 calls to checkURL). I'd rewrite it to be iterative, like so:
def checkUrl(url): # Only downloads headers, returns status code.
    while True:
        try:
            p = urlparse(url)
            conn = httplib.HTTPConnection(p.netloc)
            conn.request('HEAD', p.path)
            resp = conn.getresponse()
            return resp.status
        except IOError as e:
            if e.errno == 101:
                print "Network Error"
                time.sleep(1)
        except:
            raise

Also, you want the last clause in your try to be a bare except not an else. Your else only gets executed if control falls through the try suite, which can never happen, since the last statement of the try suite is return.
This is very easy to change to allow a limited number of retries. Just change the while True: line to for _ in xrange(5) or however many retries you wish to accept. The function will then return None if it can't connect to the site after 5 attempts. You can have it return something else or raise an exception by adding return or raise SomeException at the very end of the function (indented the same as the for or while line).

A:

If you just want to handle this Network is unreachable 101, and let other exceptions throw an error, you can do following for example.
from errno import ENETUNREACH

try:
    # tricky code goes here

except IOError as e:
    # an IOError exception occurred (socket.error is a subclass)
    if e.errno == ENETUNREACH:
        # now we had the error code 101, network unreachable
        do_some_recovery
    else:
        # other exceptions we reraise again
        raise

