Python 实现主机存活探测(Ping)

一、背景

当我们在一个可能会出现断网的环境,或者需要对主机进行实时存活检测时,就需要对主机发送ping信号来检测主机是否在线
,注意有的内部网络会对ping命令进行一定的拦截,当发送的ICMP(ping)包达到一定的上限时会进行封禁或者拦截等。

二、代码实现

基本想法,通过判断局域网内指定数量的主机,只要有一台主机断开连接,则表示内部网络已经断开。
判断条件可以进行动态调整
import os
import sys
import json
import time
import redis
import subprocess
from datetime import datetime

if getattr(sys, 'frozen', False):			# 我们对python程序打包时会将一个变量frozen注入到sys中
    APPLICATION_PATH = os.path.dirname(sys.executable)
else:
    APPLICATION_PATH = os.path.dirname('.')
config = json.load(open(os.path.join(APPLICATION_PATH, "config.json"), encoding='utf-8'))

REDIS_CONF = config.get("REDIS",{})

"""
0 表示连接成功
1 表示连接失败
"""
class HostAlive(object):
    def __init__(self,
                host=REDIS_CONF.get("HOST",None),
                port=int(REDIS_CONF.get('PORT',6379)),
                db=int(REDIS_CONF.get("DB",2)),
                password=REDIS_CONF.get("PASSWORD",None)):
        self.host = host
        self.port = port
        self.db = db
        self.password = password
        if not hasattr(HostAlive,'pool'):
            HostAlive.create_pool(host,port,db,password)
        self._connection = redis.Redis(connection_pool = HostAlive.pool)

    @staticmethod
    def create_pool(host,port,db,password):
        HostAlive.pool = redis.ConnectionPool(
            host = host,
            port = port,
            db = db,
            password = password,
            socket_connect_timeout = 2
        )

    def save_redis(self,status):
        if status == 1:
            print("内部网络连接已断开")
        else:
            print("内部网络连接正常")
        ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        data = {
            "ts": ts,
            "status": status
        }
        self._connection.hmset("network_status",data)

    def ping_host(self,ip):
        res = subprocess.run(['ping', '-n', '2', '-w', '500', ip],stdout=subprocess.PIPE)
        return_ret = str(res.stdout.decode('gbk'))
        if '时间' in return_ret and '字节' in return_ret:     # 0 表示成功
            status = 0
            print(f"[{ip}] 连接成功")
        else:
            print(f"[{ip}] 连接失败")
            status = 1                                        # 1 表示失败
        host_status.append(status)
        return status
        

if __name__ == '__main__':
    ip_list = [f"192.168.0.{i}" for i in range(1,9)]
    ha = HostAlive()
    while True:
        host_status = []
        for ip in ip_list:
            status = ha.ping_host(ip)
            if status == 1:         # 若存在一台主机断网则表示内部网络已断开并写入redis
              break
        ha.save_redis(status)
        time.sleep(10)

关于使用subprocess模块,而不是用os.system() 这个方法
因为os.system()返回的结果不是很准确,只返回0或者1来表示连接是否从或者失败,一定情况下会存在检测结果错误。
subprocess 可以对取出执行的结果,操作性更高。stdout=subprocess.PIPE 表示不打印执行的内容

  • Ping 命令参数
C:\Users\RION>ping -h
选项 -h 不正确。

用法: ping [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS]
            [-r count] [-s count] [[-j host-list] | [-k host-list]]
            [-w timeout] [-R] [-S srcaddr] [-c compartment] [-p]
            [-4] [-6] target_name

选项:
    -t             Ping 指定的主机,直到停止。
                   若要查看统计信息并继续操作,请键入 Ctrl+Break;
                   若要停止,请键入 Ctrl+C。
    -a             将地址解析为主机名。
    -n count       要发送的回显请求数。
    -l size        发送缓冲区大小。
    -f             在数据包中设置“不分段”标记(仅适用于 IPv4)。
    -i TTL         生存时间。
    -v TOS         服务类型(仅适用于 IPv4。该设置已被弃用,
                   对 IP 标头中的服务类型字段没有任何
                   影响)。
    -r count       记录计数跃点的路由(仅适用于 IPv4)。
    -s count       计数跃点的时间戳(仅适用于 IPv4)。
    -j host-list   与主机列表一起使用的松散源路由(仅适用于 IPv4)。
    -k host-list    与主机列表一起使用的严格源路由(仅适用于 IPv4)。
    -w timeout     等待每次回复的超时时间(毫秒)。
    -R             同样使用路由标头测试反向路由(仅适用于 IPv6)。
                   根据 RFC 5095,已弃用此路由标头。
                   如果使用此标头,某些系统可能丢弃
                   回显请求。
    -S srcaddr     要使用的源地址。
    -c compartment 路由隔离舱标识符。
    -p             Ping Hyper-V 网络虚拟化提供程序地址。
    -4             强制使用 IPv4。
    -6             强制使用 IPv6。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值