Скрипт для быстрой проверки доступности 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__":
: Этот блок гарантирует, что код, находящийся внутри него, будет выполнен только при запуске скрипта как основной программы, а не при импорте его как модуля в другой скрипт.
Как использовать:
- Сохраним скрипт в файл, например,
ip_checker.py
. - Запустим скрипт из командной строки:
python ip_checker.py
- Отредактируем список
ip_addresses
в скрипте, чтобы включить IP-адреса, которые мы хотим проверить. Мы также можем раскомментировать и изменить код для чтения IP-адресов из файлаip_list.txt
. Создадим этот файл и поместим в него каждый IP-адрес на отдельной строке. - Настроим количество потоков (по желанию): Изменим значение
num_threads
в вызове функцииcheck_ips
, чтобы изменить количество потоков, используемых для проверки.
Обратить внимание:
Использование большого количества потоков:
Использование слишком большого количества потоков может привести к перегрузке сети и снижению производительности. Рекомендуется начинать с небольшого количества потоков (например, 4) и постепенно увеличивать его, пока не будет достигнута оптимальная производительность.
Зависимость от ping
:
Скрипт использует команду ping
, которая может быть недоступна на некоторых системах или заблокирована брандмауэром.
Права доступа:
Для запуска команды ping
могут потребоваться права администратора на некоторых системах.