Перейти к содержимому

Скрипт для быстрой проверки доступности IP-адресов. Многопоточность.

Скрипт для быстрой проверки доступности IP-адресов. Многопоточность.

Этот скрипт использует многопоточность для быстрой проверки доступности IP-адресов. Он создает потоки для параллельного выполнения команды ping, обрабатывает результаты и выводит информацию о доступности каждого IP-адреса. Скрипт также включает обработку ошибок, таких как таймаут ping, и предоставляет гибкие настройки (например, количество потоков) для повышения производительности. В скрипте предусмотрен пример работы с файлом для считывания списка IP-адресов.

import sys
import subprocess
import threading
import queue

# 1. Импортируем необходимые модули:
#    - sys: Для взаимодействия с интерпретатором (не используется в этой версии,
#    но может быть полезно для обработки аргументов командной строки).
#    - subprocess: Для запуска внешних процессов (команды ping).
#    - threading: Для создания и управления потоками (многопоточность).
#    - queue: Для безопасной передачи данных между потоками.

def ping_ip(ip_address, results_queue):
    """Пингует заданный IP-адрес и добавляет результат в очередь."""
    # 2. Определяем функцию ping_ip, которая выполняет пинг одного IP-адреса.
    #    Она принимает два аргумента:
    #    - ip_address: IP-адрес для пинга.
    #    - results_queue: Объект очереди для передачи результатов.
    try:
        ping_reply = subprocess.call(
            ["ping", ip_address, "-n", "1"],  # "-n 1" для Windows, "-c 1" для Linux/macOS
            # 3. Пытаемся выполнить команду ping.
            #    - subprocess.call запускает команду и ждет ее завершения.
            #    - Команда ping используется для проверки доступности IP-адреса.
            #    - ["ping", ip_address, "-n", "1"] - это список, представляющий команду.
            #      Для Windows используется "-n 1" (отправить 1 пакет).  Для Linux/macOS "-c 1"  (отправить 1 пакет)
            #    - stdout=subprocess.DEVNULL и stderr=subprocess.DEVNULL перенаправляют вывод и ошибки в никуда,
            #      чтобы не засорять вывод.
            #    - timeout=2:  Устанавливает таймаут в 2 секунды. Если ping не ответит в течение 2 секунд,
            #      будет сгенерировано исключение TimeoutExpired.
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            timeout=2  # Добавляем таймаут, чтобы не зависать на недоступных хостах
        )

        if ping_reply == 0:
            results_queue.put((ip_address, True))
            # 4. Если ping_reply равен 0, значит, IP-адрес доступен.
            #    Результат (IP-адрес, True) помещается в очередь results_queue.
        else:
            results_queue.put((ip_address, False))
            # 5. Если ping_reply не равен 0, значит, IP-адрес недоступен.
            #    Результат (IP-адрес, False) помещается в очередь results_queue.
    except subprocess.TimeoutExpired:
        results_queue.put((ip_address, False))  # Обработка случая таймаута
        # 6. Если возникло исключение TimeoutExpired (таймаут ping), считаем IP-адрес недоступным.
        #    Результат (IP-адрес, False) помещается в очередь results_queue.

def check_ips(ip_list, num_threads=4):  # По умолчанию 4 потока
    """Проверяет список IP-адресов, используя многопоточность."""
    # 7. Определяем функцию check_ips, которая проверяет список IP-адресов.
    #    Она принимает два аргумента:
    #    - ip_list: Список IP-адресов для проверки.
    #    - num_threads: Количество потоков для использования (по умолчанию 4).
    results_queue = queue.Queue()  # Очередь для хранения результатов
    # 8. Создаем очередь результатов (results_queue).  Очередь используется для безопасной передачи
    #    результатов между потоками.

    threads = []
    # 9. Создаем пустой список threads для хранения объектов потоков.
    for ip in ip_list:
        ip = ip.strip()  # Удаляем пробельные символы и переводы строк
        # 10. Итерируемся по списку IP-адресов.
        #     Для каждого IP-адреса:
        #     - ip.strip() удаляет пробелы в начале и в конце строки IP-адреса,
        #       а также переводы строк (важно при чтении из файла).
        if ip: # Ignore empty strings
            # 11. Проверяем, что IP-адрес не пустой. Это необходимо, чтобы избежать ошибок.
            thread = threading.Thread(target=ping_ip, args=(ip, results_queue))
            # 12. Создаем новый поток (thread).
            #     - threading.Thread создает новый поток.
            #     - target=ping_ip указывает, какую функцию (ping_ip) нужно запустить в потоке.
            #     - args=(ip, results_queue) передает аргументы функции ping_ip (IP-адрес и очередь результатов).
            threads.append(thread)
            # 13. Добавляем созданный поток в список threads.
            thread.start()
            # 14. Запускаем поток. Метод start() вызывает функцию, указанную в аргументе target,
            #     в отдельном потоке.

    # Ждем завершения всех потоков
    for thread in threads:
        thread.join()
        # 15. После запуска всех потоков, ждем, пока они завершат свою работу.
        #     - thread.join() приостанавливает выполнение текущего потока (основного потока)
        #       до тех пор, пока поток thread не завершится.

    # Собираем результаты из очереди
    results = []
    # 16. Создаем пустой список results для хранения результатов проверки.
    while not results_queue.empty():
        results.append(results_queue.get())
        # 17. Пока очередь результатов не пуста:
        #     - results_queue.get() извлекает элемент из очереди (результат пинга).
        #     - Результат (IP-адрес и флаг доступности) добавляется в список results.

    return results
    # 18. Функция возвращает список results.

if __name__ == "__main__":
    # 19.  Этот блок кода выполняется только при запуске скрипта напрямую (не при импорте).
    # Пример использования
    ip_addresses = ["127.0.0.1", "8.8.8.8", "192.168.1.100", "example.com"]
    # 20.  Создаем список ip_addresses, содержащий IP-адреса для проверки.
    # Можно считывать IP-адреса из файла, если нужно:
    # with open("ip_list.txt", "r") as f:
    #     ip_addresses = f.readlines()
    # 21.  Пример кода для чтения IP-адресов из файла (закомментировано).
    #      -  Открывает файл "ip_list.txt" для чтения.
    #      -  f.readlines() считывает все строки из файла в список.

    results = check_ips(ip_addresses, num_threads=4)  # Проверяем с 4 потоками
    # 22.  Вызываем функцию check_ips для проверки IP-адресов.
    #      - Передаем список ip_addresses.
    #      - num_threads=4 указывает, что нужно использовать 4 потока.

    for ip, reachable in results:
        # 23. Итерируемся по результатам.  Каждый элемент в results - это кортеж (IP-адрес, доступность).
        if reachable:
            print(f"* {ip} is reachable")
            # 24. Если IP-адрес доступен (reachable is True), выводим сообщение об этом.
        else:
            print(f"* {ip} is NOT reachable")
            # 25. Если IP-адрес недоступен (reachable is False), выводим сообщение об этом.

 

Пояснения

  • Многопоточность: Скрипт использует threading для одновременной проверки нескольких IP-адресов. Это значительно ускоряет процесс, особенно при большом списке IP-адресов. Функция check_ips запускает несколько потоков, каждый из которых пингует свой IP-адрес.
  • Очередь результатов (queue.Queue): Используется queue.Queue для безопасной передачи результатов из потоков в главный поток. Это необходимо, чтобы избежать проблем с синхронизацией при записи в общую структуру данных из нескольких потоков.
  • Функция ping_ip: Эта функция выполняет пинг отдельного IP-адреса. Она упрощает структуру кода и делает его более читаемым.
  • Обработка ошибок (TimeoutExpired): Добавлена обработка исключения subprocess.TimeoutExpired. Это важно, чтобы скрипт не зависал навсегда, если IP-адрес недоступен и не отвечает на ping-запросы. Установлен таймаут в 2 секунды.
  • Удаление пробельных символов: ip = ip.strip() удаляет любые пробельные символы (включая переводы строк) в начале и конце IP-адреса. Это предотвращает проблемы, если IP-адреса считываются из файла.
  • Проверка на пустые строки: if ip: игнорирует пустые строки, что полезно при чтении из файла.
  • Гибкая настройка количества потоков: Функция check_ips принимает аргумент num_threads, который позволяет настроить количество используемых потоков. По умолчанию используется 4 потока.
  • Универсальность для разных ОС: Команда ping адаптирована для работы как в Windows ( -n 1), так и в Linux/macOS (команда ping без изменений, т.к. по умолчанию отправляется один пакет). Для большей уверенности можно сделать проверку операционной системы и выбирать нужный параметр. Но для текущей задачи достаточно -n 1 для Windows, так как это синтаксис, поддерживаемый Windows.
  • Чтение из файла (пример): Приведен пример кода, как можно считывать IP-адреса из текстового файла.
  • if __name__ == "__main__":: Этот блок гарантирует, что код, находящийся внутри него, будет выполнен только при запуске скрипта как основной программы, а не при импорте его как модуля в другой скрипт.

Как использовать:

  1. Сохраним скрипт в файл, например, ip_checker.py.
  2. Запустим скрипт из командной строки: python ip_checker.py
  3. Отредактируем список ip_addresses в скрипте, чтобы включить IP-адреса, которые мы хотим проверить. Мы также можем раскомментировать и изменить код для чтения IP-адресов из файла ip_list.txt. Создадим этот файл и поместим в него каждый IP-адрес на отдельной строке.
  4. Настроим количество потоков (по желанию): Изменим значение num_threads в вызове функции check_ips, чтобы изменить количество потоков, используемых для проверки.

Обратить внимание:

Использование большого количества потоков:

Использование слишком большого количества потоков может привести к перегрузке сети и снижению производительности. Рекомендуется начинать с небольшого количества потоков (например, 4) и постепенно увеличивать его, пока не будет достигнута оптимальная производительность.

Зависимость от ping: 

Скрипт использует команду ping, которая может быть недоступна на некоторых системах или заблокирована брандмауэром.

Права доступа: 

Для запуска команды ping могут потребоваться права администратора на некоторых системах.

Конспект:
Четверг, 07 августа 2025
Скрипт для быстрой проверки доступности IP-адресов. Многопоточность.