14

I'm translating hostname to IPv4 address using gethostbyname() of socket in python. Sometimes it takes little extra time to show the IP address. I was wondering if there is any default timeout value for each lookup. Here's how i'm using socket in my program-

try:
    addr = socket.gethostbyname(hostname)
except socket.gaierror:
    addr = "" 
print hostname+" : "+addr

Just need to add another question, is there any chance that this can miss any IP address? Anyone had any experience converting large sample of hostname to IP address?

saz
  • 955
  • 5
  • 15
  • 26
  • There doesn't seem to be a way to control the timeout of `gethostbyname`, but you could rather set the default timeout of the socket object with `socket.setdefaulttimeout(timeout)`. – Lord Henry Wotton Dec 05 '14 at 21:03
  • @LordHenryWotton that can be done but i'm wondering if anyone found any IP addresses mismatch and it misses any IP using gethostbyname(). if it misses then setting timeout value would solve it or not. – saz Dec 05 '14 at 21:27
  • 5
    @LordHenryWotton: I doubt that `socket.setdefaulttimeout` affects `gethostbyname`. I think it will only affect operations on specific sockets, that is read, write, connect. But `socket.gethostbyname` is not an operation on a specific socket but instead a blocking call into libc gethostbyname(3). See also http://www.gossamer-threads.com/lists/python/python/790534 – Steffen Ullrich Dec 05 '14 at 21:55

3 Answers3

3

Here's an example of using the alarm signal (for posix type systems) to set a timeout for socket.gethostbyname:

Setup code:

from contextlib import contextmanager
import signal

def raise_error(signum, frame):
    """This handler will raise an error inside gethostbyname"""
    raise OSError

@contextmanager
def set_signal(signum, handler):
    """Temporarily set signal"""
    old_handler = signal.getsignal(signum)
    signal.signal(signum, handler)
    try:
        yield
    finally:
        signal.signal(signum, old_handler)

@contextmanager
def set_alarm(time):
    """Temporarily set alarm"""
    signal.setitimer(signal.ITIMER_REAL, time)
    try:
        yield
    finally:
        signal.setitimer(signal.ITIMER_REAL, 0) # Disable alarm

@contextmanager
def raise_on_timeout(time):
    """This context manager will raise an OSError unless
    The with scope is exited in time."""
    with set_signal(signal.SIGALRM, raise_error):
        with set_alarm(time): 
            yield

Execution code

import socket
try:
    with raise_on_timeout(0.1): # Timeout in 100 milliseconds
        print(socket.gethostbyname(socket.gethostname()))
except OSError:
    print("Could not gethostbyname in time")
Bryce Guinta
  • 3,456
  • 1
  • 35
  • 36
2

Here is the entire Socket time out file.

import socket

try:
    _GLOBAL_DEFAULT_TIMEOUT = socket._GLOBAL_DEFAULT_TIMEOUT
except AttributeError:
    _GLOBAL_DEFAULT_TIMEOUT = object()

As you can see, GLOBAL_DEFAULT_TIMEOUT = object() is a just creating an empty object.

socket.setsocketimeout will set the default timeout for new sockets, however if you're not using the sockets directly, the setting can be easily overwritten.

For more, see this answer.

EDIT: As for your follow up question, yes. I made a program that involved host name to IP address conversion, and I did have issues with it missing addresses. Not sure if this was because of a timeout. I just had to double check.

Community
  • 1
  • 1
David Greydanus
  • 2,551
  • 1
  • 23
  • 42
  • Thanks. just wondering, have you done anything in the program to solve missing address problem or just manually double checked? – saz Dec 06 '14 at 18:39
  • Nothing to smart or fancy. I just had the program loop more than once, and it usually worked fine. – David Greydanus Dec 06 '14 at 19:09
0

A simple solution would be:

import socket
socket.setdefaulttimeout(5) #Default this is 30
socket.gethostbyname(your_url)