|
|
@@ -0,0 +1,372 @@
|
|
|
+import tkinter as tk
|
|
|
+from tkinter import messagebox, ttk
|
|
|
+import sqlite3
|
|
|
+import socket
|
|
|
+import requests
|
|
|
+import uuid
|
|
|
+import psutil
|
|
|
+import netifaces
|
|
|
+from pythonping import ping as python_ping
|
|
|
+import time
|
|
|
+import os
|
|
|
+
|
|
|
+# *** Утилитарные функции ***
|
|
|
+
|
|
|
+def get_size(bytes_count):
|
|
|
+ """
|
|
|
+ Преобразует байты в удобочитаемый формат (B, KB, MB, GB, TB).
|
|
|
+ """
|
|
|
+ if not isinstance(bytes_count, (int, float)) or bytes_count is None:
|
|
|
+ return "N/A"
|
|
|
+
|
|
|
+ for unit in ['B', 'KB', 'MB', 'GB', 'TB', 'PB']:
|
|
|
+ if bytes_count < 1024.0:
|
|
|
+ return f"{bytes_count:.2f} {unit}"
|
|
|
+ bytes_count /= 1024.0
|
|
|
+ return f"{bytes_count:.2f} PB"
|
|
|
+
|
|
|
+def format_report(data, target_host):
|
|
|
+ """
|
|
|
+ Форматирует все собранные данные в одну строку для вывода в файл и консоль.
|
|
|
+ """
|
|
|
+ # Добавляем метку времени начала отчета
|
|
|
+ timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
+
|
|
|
+ report_lines = []
|
|
|
+ report_lines.append("="*50)
|
|
|
+ report_lines.append(" СВОДНАЯ ИНФОРМАЦИЯ О СЕТИ")
|
|
|
+ report_lines.append("="*50)
|
|
|
+ report_lines.append(f"Дата и время отчета: {timestamp}")
|
|
|
+ report_lines.append("-" * 30)
|
|
|
+
|
|
|
+ # Блок 1: Системная информация
|
|
|
+ report_lines.append("🖥️ Система:")
|
|
|
+ report_lines.append(f" Имя компьютера: {data.get('hostname', 'N/A')}")
|
|
|
+ report_lines.append(f" Сетевой адаптер: {data.get('interface_name', 'N/A')}")
|
|
|
+ report_lines.append(f" MAC-адрес: {data.get('mac_address', 'N/A')}")
|
|
|
+ report_lines.append("-" * 30)
|
|
|
+
|
|
|
+ # Блок 2: IP-адреса и шлюз
|
|
|
+ report_lines.append(f"🌐 IP-адреса:")
|
|
|
+ report_lines.append(f" Внутренний IP: {data.get('local_ip', 'N/A')}")
|
|
|
+ report_lines.append(f" IP шлюза (роутера): {data.get('gateway_ip', 'N/A')}")
|
|
|
+ report_lines.append(f" Внешний IP: {data.get('external_ip', 'N/A')}")
|
|
|
+ report_lines.append("-" * 30)
|
|
|
+
|
|
|
+ # Блок 3: Объем данных
|
|
|
+ report_lines.append(f"📊 Общий объем данных (с момента загрузки ОС):")
|
|
|
+ report_lines.append(f" Отправлено: {get_size(data.get('total_sent'))}")
|
|
|
+ report_lines.append(f" Получено: {get_size(data.get('total_recv'))}")
|
|
|
+ report_lines.append("-" * 30)
|
|
|
+
|
|
|
+ # Блок 4: Пинг
|
|
|
+ report_lines.append(f"⏱️ Пинг и потеря пакетов:")
|
|
|
+
|
|
|
+ # Пинг до шлюза
|
|
|
+ report_lines.append(f" - До шлюза ({data.get('gateway_ip', 'N/A')}):")
|
|
|
+ ping_gw = data.get('ping_gateway_ms')
|
|
|
+ loss_gw = data.get('loss_gateway_percent')
|
|
|
+ if ping_gw is not None:
|
|
|
+ report_lines.append(f" Средний пинг: {ping_gw:.2f} мс")
|
|
|
+ report_lines.append(f" Потеря пакетов: {loss_gw:.2f}%")
|
|
|
+ else:
|
|
|
+ report_lines.append(" Не удалось проверить.")
|
|
|
+
|
|
|
+ # Пинг до ya.ru
|
|
|
+ report_lines.append(f" - До {target_host}:")
|
|
|
+ ping_ext = data.get('ping_ya_ru_ms')
|
|
|
+ loss_ext = data.get('loss_ya_ru_percent')
|
|
|
+ if ping_ext is not None:
|
|
|
+ report_lines.append(f" Средний пинг: {ping_ext:.2f} мс")
|
|
|
+ report_lines.append(f" Потеря пакетов: {loss_ext:.2f}%")
|
|
|
+ else:
|
|
|
+ report_lines.append(" Не удалось проверить (проверьте подключение к Интернету).")
|
|
|
+ report_lines.append("-" * 30)
|
|
|
+
|
|
|
+ # Блок 5: Скорость
|
|
|
+ report_lines.append(f"📶 Скорость Интернета (Yandex Internet Speed Test):")
|
|
|
+ dl_speed = data.get('download_speed_mbps')
|
|
|
+ ul_speed = data.get('upload_speed_mbps')
|
|
|
+
|
|
|
+ if dl_speed is not None:
|
|
|
+ report_lines.append(f" Скорость загрузки: {dl_speed:.2f} Мбит/с")
|
|
|
+ report_lines.append(f" Скорость выгрузки: {ul_speed:.2f} Мбит/с")
|
|
|
+ else:
|
|
|
+ report_lines.append(" Тестирование скорости не было выполнено или завершилось ошибкой.")
|
|
|
+
|
|
|
+ report_lines.append("="*50)
|
|
|
+
|
|
|
+ return "\n".join(report_lines)
|
|
|
+
|
|
|
+# *** Функции для измерений ***
|
|
|
+
|
|
|
+def get_network_io_total():
|
|
|
+ """Получает общий объем отправленных и полученных данных."""
|
|
|
+ try:
|
|
|
+ net_io = psutil.net_io_counters()
|
|
|
+ return {"total_sent": net_io.bytes_sent, "total_recv": net_io.bytes_recv}
|
|
|
+ except Exception:
|
|
|
+ return None
|
|
|
+
|
|
|
+def yandex_internet_speed_test():
|
|
|
+ """
|
|
|
+ Используем API Yandex для проверки скорости Интернета.
|
|
|
+ Функция возвращает скорость загрузки и выгрузки в мегабитах в секунду.
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ # Подставьте ваш уникальный токен Yandex API здесь!
|
|
|
+ headers = {'Authorization': 'Bearer YOUR_YANDEX_API_TOKEN'}
|
|
|
+ response = requests.post(
|
|
|
+ 'https://speed.yandex.com/api/v1/test',
|
|
|
+ headers=headers,
|
|
|
+ json={"duration": 10}, # длительность теста, сек
|
|
|
+ timeout=15
|
|
|
+ )
|
|
|
+ response.raise_for_status()
|
|
|
+ results = response.json()
|
|
|
+ download_speed = results.get('download_speed', None)
|
|
|
+ upload_speed = results.get('upload_speed', None)
|
|
|
+
|
|
|
+ return {
|
|
|
+ "download_speed_mbps": download_speed,
|
|
|
+ "upload_speed_mbps": upload_speed
|
|
|
+ }
|
|
|
+ except Exception as ex:
|
|
|
+ print(f"Произошла ошибка при тестировании скорости: {ex}")
|
|
|
+ return None
|
|
|
+
|
|
|
+def get_ping_and_loss(target, count=4):
|
|
|
+ """Измеряет средний пинг и процент потери пакетов."""
|
|
|
+ try:
|
|
|
+ result = python_ping(target, count=count, timeout=2)
|
|
|
+ return {"avg_ping_ms": result.rtt_avg_ms, "packet_loss_percent": result.packet_loss}
|
|
|
+ except Exception:
|
|
|
+ return None
|
|
|
+
|
|
|
+def get_local_net_details():
|
|
|
+ """Получает локальный IP, MAC-адрес, имя активного интерфейса и IP шлюза."""
|
|
|
+ details = {"local_ip": None, "mac_address": None, "interface_name": None, "gateway_ip": None}
|
|
|
+
|
|
|
+ try:
|
|
|
+ gws = netifaces.gateways()
|
|
|
+ default_route = gws.get('default', {}).get(netifaces.AF_INET)
|
|
|
+
|
|
|
+ if default_route:
|
|
|
+ details['gateway_ip'] = default_route[0]
|
|
|
+ active_interface = default_route[1]
|
|
|
+ details['interface_name'] = active_interface
|
|
|
+
|
|
|
+ addrs = netifaces.ifaddresses(active_interface)
|
|
|
+
|
|
|
+ if netifaces.AF_INET in addrs:
|
|
|
+ details['local_ip'] = addrs[netifaces.AF_INET][0]['addr']
|
|
|
+
|
|
|
+ if netifaces.AF_LINK in addrs:
|
|
|
+ details['mac_address'] = addrs[netifaces.AF_LINK][0]['addr'].upper().replace('-', ':')
|
|
|
+
|
|
|
+ except Exception:
|
|
|
+ pass
|
|
|
+ return details
|
|
|
+
|
|
|
+def get_system_info():
|
|
|
+ """Собирает имя хоста и внешний IP."""
|
|
|
+ info = {"hostname": None, "external_ip": None}
|
|
|
+
|
|
|
+ try:
|
|
|
+ info["hostname"] = socket.gethostname()
|
|
|
+ except:
|
|
|
+ pass
|
|
|
+
|
|
|
+ try:
|
|
|
+ response = requests.get('https://api.ipify.org?format=json', timeout=5)
|
|
|
+ response.raise_for_status()
|
|
|
+ info["external_ip"] = response.json().get('ip')
|
|
|
+ except:
|
|
|
+ pass
|
|
|
+
|
|
|
+ return info
|
|
|
+
|
|
|
+# *** Функции для взаимодействия с базой данных ***
|
|
|
+
|
|
|
+def create_database_and_table(db_file):
|
|
|
+ """
|
|
|
+ Создает базу данных и таблицу NetworkInfo, если они отсутствуют.
|
|
|
+ """
|
|
|
+ conn = sqlite3.connect(db_file)
|
|
|
+ cursor = conn.cursor()
|
|
|
+
|
|
|
+ # Создание таблицы NetworkInfo
|
|
|
+ cursor.execute('''
|
|
|
+ CREATE TABLE IF NOT EXISTS NetworkInfo (
|
|
|
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
+ hostname TEXT,
|
|
|
+ mac_address TEXT,
|
|
|
+ local_ip TEXT,
|
|
|
+ gateway_ip TEXT,
|
|
|
+ external_ip TEXT,
|
|
|
+ total_sent TEXT,
|
|
|
+ total_recv TEXT,
|
|
|
+ ping_gateway_ms REAL,
|
|
|
+ loss_gateway_percent REAL,
|
|
|
+ ping_ya_ru_ms REAL,
|
|
|
+ loss_ya_ru_percent REAL,
|
|
|
+ download_speed_mbps REAL,
|
|
|
+ upload_speed_mbps REAL,
|
|
|
+ server_name TEXT,
|
|
|
+ server_location TEXT,
|
|
|
+ server_latency REAL,
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
+ )
|
|
|
+ ''')
|
|
|
+
|
|
|
+ conn.commit()
|
|
|
+ conn.close()
|
|
|
+
|
|
|
+def save_to_db(db_file, data):
|
|
|
+ """
|
|
|
+ Сохраняет данные в базу данных.
|
|
|
+ """
|
|
|
+ conn = sqlite3.connect(db_file)
|
|
|
+ cursor = conn.cursor()
|
|
|
+
|
|
|
+ # Заполняем поля из data
|
|
|
+ sql_insert_query = '''
|
|
|
+ INSERT INTO NetworkInfo (
|
|
|
+ hostname, mac_address, local_ip, gateway_ip, external_ip, total_sent, total_recv,
|
|
|
+ ping_gateway_ms, loss_gateway_percent, ping_ya_ru_ms, loss_ya_ru_percent,
|
|
|
+ download_speed_mbps, upload_speed_mbps, server_name, server_location, server_latency
|
|
|
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
+ '''
|
|
|
+
|
|
|
+ values = [
|
|
|
+ data.get('hostname'), data.get('mac_address'), data.get('local_ip'),
|
|
|
+ data.get('gateway_ip'), data.get('external_ip'), data.get('total_sent'),
|
|
|
+ data.get('total_recv'), data.get('ping_gateway_ms'), data.get('loss_gateway_percent'),
|
|
|
+ data.get('ping_ya_ru_ms'), data.get('loss_ya_ru_percent'), data.get('download_speed_mbps'),
|
|
|
+ data.get('upload_speed_mbps'), data.get('server_name'), data.get('server_location'),
|
|
|
+ data.get('server_latency')
|
|
|
+ ]
|
|
|
+
|
|
|
+ cursor.execute(sql_insert_query, values)
|
|
|
+ conn.commit()
|
|
|
+ conn.close()
|
|
|
+
|
|
|
+def view_database(db_file):
|
|
|
+ """
|
|
|
+ Возвращает список всех записей из базы данных.
|
|
|
+ """
|
|
|
+ conn = sqlite3.connect(db_file)
|
|
|
+ cursor = conn.cursor()
|
|
|
+
|
|
|
+ # Извлекаем все строки из таблицы
|
|
|
+ cursor.execute("SELECT * FROM NetworkInfo ORDER BY created_at ASC;")
|
|
|
+ rows = cursor.fetchall()
|
|
|
+
|
|
|
+ conn.close()
|
|
|
+ return rows
|
|
|
+
|
|
|
+# *** Графический интерфейс ***
|
|
|
+
|
|
|
+class App(tk.Tk):
|
|
|
+ def __init__(self):
|
|
|
+ super().__init__()
|
|
|
+ self.title("Мониторинг сети")
|
|
|
+ self.geometry("800x600") # Окно размером 800х600 пикселей
|
|
|
+ self.create_widgets()
|
|
|
+ self.db_file = 'network_reports.db'
|
|
|
+ create_database_and_table(self.db_file)
|
|
|
+
|
|
|
+ def create_widgets(self):
|
|
|
+ frame_buttons = ttk.Frame(self)
|
|
|
+ frame_buttons.pack(pady=(10, 10))
|
|
|
+
|
|
|
+ btn_collect = ttk.Button(frame_buttons, text="Запустить мониторинг", command=self.collect_data)
|
|
|
+ btn_view = ttk.Button(frame_buttons, text="Просмотреть отчёты", command=self.view_reports)
|
|
|
+ btn_exit = ttk.Button(frame_buttons, text="Выход", command=self.quit)
|
|
|
+
|
|
|
+ btn_collect.grid(row=0, column=0, padx=10)
|
|
|
+ btn_view.grid(row=0, column=1, padx=10)
|
|
|
+ btn_exit.grid(row=0, column=2, padx=10)
|
|
|
+
|
|
|
+ # Таблица для просмотра результатов мониторинга
|
|
|
+ columns = ("id", "hostname", "mac_address", "local_ip", "gateway_ip", "external_ip",
|
|
|
+ "total_sent", "total_recv", "ping_gateway_ms", "loss_gateway_percent",
|
|
|
+ "ping_ya_ru_ms", "loss_ya_ru_percent", "download_speed_mbps", "upload_speed_mbps",
|
|
|
+ "server_name", "server_location", "server_latency", "created_at")
|
|
|
+ self.tree = ttk.Treeview(self, columns=columns, show="headings")
|
|
|
+ self.tree.pack(fill=tk.BOTH, expand=True)
|
|
|
+
|
|
|
+ for col in columns:
|
|
|
+ self.tree.heading(col, text=col.capitalize(), anchor=tk.W)
|
|
|
+ self.tree.column(col, width=100, stretch=False)
|
|
|
+
|
|
|
+ def collect_data(self):
|
|
|
+ """
|
|
|
+ Собирает всю необходимую информацию и сохраняет её в базу данных.
|
|
|
+ """
|
|
|
+ data = {}
|
|
|
+ target_host = 'ya.ru'
|
|
|
+ output_filename = "network_info_report.txt"
|
|
|
+
|
|
|
+ # Сбор данных
|
|
|
+ print("--- 1. Сбор базовой информации (IP, MAC, Hostname) ---")
|
|
|
+ data.update(get_system_info())
|
|
|
+ data.update(get_local_net_details())
|
|
|
+ io_data = get_network_io_total()
|
|
|
+ if io_data:
|
|
|
+ data.update(io_data)
|
|
|
+ print("Базовые данные собраны. ✅")
|
|
|
+
|
|
|
+ # Пинги
|
|
|
+ if data.get('gateway_ip'):
|
|
|
+ print(f"\n--- 2. Проверка пинга до шлюза ({data['gateway_ip']}) ---")
|
|
|
+ ping_gw_data = get_ping_and_loss(data['gateway_ip'])
|
|
|
+ if ping_gw_data:
|
|
|
+ data["ping_gateway_ms"] = ping_gw_data["avg_ping_ms"]
|
|
|
+ data["loss_gateway_percent"] = ping_gw_data["packet_loss_percent"]
|
|
|
+ print("Проверка завершена. 📶")
|
|
|
+
|
|
|
+ print(f"\n--- 3. Проверка пинга до {target_host} ---")
|
|
|
+ ping_ext_data = get_ping_and_loss(target=target_host)
|
|
|
+ if ping_ext_data:
|
|
|
+ data["ping_ya_ru_ms"] = ping_ext_data["avg_ping_ms"]
|
|
|
+ data["loss_ya_ru_percent"] = ping_ext_data["packet_loss_percent"]
|
|
|
+ print("Проверка завершена. 🎯")
|
|
|
+
|
|
|
+ # Скорость через Yandex SpeedTest
|
|
|
+ print("\n--- 4. Проверка скорости сети (Yandex Speedtest) ---")
|
|
|
+ speed_data = yandex_internet_speed_test()
|
|
|
+ if speed_data:
|
|
|
+ data.update(speed_data)
|
|
|
+ print("Тестирование скорости завершено. 🚀")
|
|
|
+ else:
|
|
|
+ print("Тестирование скорости не выполнено (проверьте интернет-соединение).")
|
|
|
+
|
|
|
+ # Форматирование и вывод отчета
|
|
|
+ report_content = format_report(data, target_host)
|
|
|
+
|
|
|
+ print(report_content)
|
|
|
+
|
|
|
+ try:
|
|
|
+ with open(output_filename, 'w', encoding='utf-8') as f:
|
|
|
+ f.write(report_content)
|
|
|
+ print(f"\n✅ Отчет успешно сохранен в файле: {output_filename} в папке {os.getcwd()}")
|
|
|
+ except Exception as e:
|
|
|
+ print(f"\n❌ Ошибка при записи отчета в файл: {e}")
|
|
|
+
|
|
|
+ # Сохраняем данные в базу данных
|
|
|
+ save_to_db(self.db_file, data)
|
|
|
+ messagebox.showinfo("Готово", "Данные успешно собраны и сохранены!")
|
|
|
+
|
|
|
+ def view_reports(self):
|
|
|
+ """
|
|
|
+ Загружает и показывает данные из базы данных в таблице.
|
|
|
+ """
|
|
|
+ rows = view_database(self.db_file)
|
|
|
+ self.tree.delete(*self.tree.get_children())
|
|
|
+ for row in rows:
|
|
|
+ self.tree.insert("", tk.END, values=row)
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ app = App()
|
|
|
+ app.mainloop()
|