python check to see if host is connected to networ

2019-08-12 22:25发布

I found an option discussed here which works great if the host is connected to the network. However, socket.gethostbyname(hostname) hangs for a long time if the host is not connected.

I saw a suggestion to run socket.gethostbyname(hostname) in a thread and if this thread did not return a result within a specified period, assume it is not connected. This I thought was a good idea, but I am not proficient enough yet with threads (although I have used them successfully) to know how to do this.

I found this discussion How to find running time of a thread in Python which seems to imply that this is not trivial. Any ideas? Thanks.

Edit:

I must admit my own ignorance. I didn't realize (though I should have) that socket.gethostbyname(hostname) was doing a DNS lookup. So, I put together this simple to test for a socket connection to the host of interest on port 22:

#! /usr/bin/python

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(0.5)

try:
        s.connect(('192.168.2.5',22)) 
except Exception, e:
        print 'connection failed'

s.close() 

Note: this will not check for an existing connection to a network and will hang if not connected.

This script will check for a connection to a network first, if a connection is found then it will check for a specific host on that network:

#! /usr/bin/python

import socket
import fcntl
import struct

def check_connection():

        ifaces = ['eth0','wlan0']
        connected = []

        i = 0
        for ifname in ifaces:

            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            try:
                socket.inet_ntoa(fcntl.ioctl(
                        s.fileno(),
                        0x8915,  # SIOCGIFADDR
                        struct.pack('256s', ifname[:15])
                )[20:24])
                connected.append(ifname)
                print "%s is connected" % ifname
            except:
                print "%s is not connected" % ifname

            i += 1

        return connected

connected_ifaces = check_connection()

if len(connected_ifaces) == 0:
    print 'not connected to any network'
else:
    print 'connected to a network using the following interface(s):'
    for x in connected_ifaces:
        print '\t%s' % x

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.5)

    try:
            s.connect(('192.168.2.5',22)) 
            print 'connected to hostname'
    except Exception, e:
            print 'connection to hostname failed'

    s.close()

2条回答
狗以群分
2楼-- · 2019-08-12 23:07

There's a good chance that the blocking call to gethostbyname isn't actually necessary here.

First, you may not want to do a DNS lookup at all, and almost everything else you can do with sockets—e.g., connect—already handles timeouts.

Second, if you really do need timeouts on DNS lookup, you probably want to use an async DNS library like pycares.

But if you need timeouts on DNS lookups, and you can't rely on external code, then you're right, you will have to run the DNS lookup in another thread, and wait on it in the main thread.

So, how do you do that?

Well, you can join a thread with a timeout. Or you can wait on a Condition or Event that the background thread can signal, or, with select, on a pipe that the background thread can write to.

The simplest thing is probably join with a timeout… except that you end up leaving the background thread running after a timeout, and if you try to quit before it finishes, Python may (and will, with CPython 2.7 or 3.3 on most major platforms) wait around for it to end before quitting. The way to fix that is to use a daemon thread, but then you can't legally join it. You can daemonize it after the timeout, but I think here an Event is simpler.

So, for example:

event = threading.Event()

def blocking_dns():
    socket.gethostbyname(host)
    event.set()

thread = threading.Thread(target=blocking_dns)
thread.daemon = True
thread.start()
success = event.wait(timeout)

Here's a general-purpose wrapper:

def run_with_timeout(timeout, func, *args, **kwargs):
    event = threading.Event()
    def wrapper():
        func(*args, **kwargs)
        event.set()
    thread = threading.Thread(target=wrapper, args=args, kwargs=kwargs)
    thread.daemon = True
    thread.start()
    return event.wait(timeout)

Which you can use like this:

dns_works = run_with_timeout(5.0, socket.gethostbyname, 'www.google.com')

Using an Event for anything less trivial than this gets tricky (and often you can't see that it's tricky, and write code that works 99% of the time and is impossible to debug the other 1%). The usual problem is that you can miss the set from the background thread. If you don't care whether the set happens before you even checked, or only after you've started waiting, you can use Event; otherwise, you need Condition.

查看更多
地球回转人心会变
3楼-- · 2019-08-12 23:16

if you are on windows system you may use this

x = os.system("ping -n 1  google.com")
if x == 0: 
    print "HOST IS CONNECTED  :) "
查看更多
登录 后发表回答