Мониторинг реальной скорости сети с помощью iperf3 и VizIoT

Соответствует ли скорость вашего интернета заявленной в тарифе? Почему Wi-Fi в дальней комнате работает медленнее, чем у роутера? Чтобы получить точные ответы на эти вопросы, обычных веб-сайтов для проверки скорости недостаточно. Нужен профессиональный инструмент — iperf3.

В этом руководстве мы настроим систему автоматического мониторинга, которая будет регулярно измерять "чистую" пропускную способность вашей сети, а результаты отправлять в VizIoT для наглядной визуализации.

Конечный результат: Ваша личная панель мониторинга сети

Прежде чем мы перейдем к техническим деталям, давайте посмотрим, что у нас получится. Вы сможете создать интерактивную панель, которая в реальном времени будет отображать:

  • Скорость загрузки и отдачи до разных точек в интернете.
  • Историю производительности вашего канала, чтобы выявлять "просадки" в определённое время суток.
  • Сравнение скорости до вашего провайдера и до удалённых серверов.

Такая панель позволит вам не просто "измерить скорость", а постоянно контролировать качество вашего сетевого соединения.


Что такое iperf3 и почему он лучше обычных спидтестов?

iperf3 — это консольная утилита для измерения максимальной пропускной способности сети между двумя точками (клиентом и сервером).

В отличие от веб-сайтов, iperf3 измеряет "чистую" производительность вашего канала, исключая такие факторы, как производительность браузера, загруженность веб-сервера или влияние рекламы на странице. Это "золотой стандарт" для сетевых инженеров, который позволяет:

  • Проверить честность провайдера: Узнать реальную скорость, которую он вам предоставляет.
  • Найти "узкие места": Определить, что именно замедляет вашу локальную сеть (слабый роутер, плохой кабель).
  • Оценить производительность Wi-Fi: Сравнить скорость в разных частях дома.

Как мы будем измерять скорость?

Наш скрипт будет использовать три ключевых режима для получения полной картины:

  1. Отдача (Upload): Ваш компьютер отправляет данные на сервер. Этот тест показывает, как быстро вы можете загружать файлы в интернет.
  2. Загрузка (Download): Сервер отправляет данные вам. Это то, что обычно называют "скоростью интернета".
  3. Двунаправленный (Bidirectional): Данные передаются в обе стороны одновременно. Это стресс-тест, показывающий, как сеть справляется с комплексной нагрузкой (например, видеозвонок + загрузка файла).

Как это сделать: Пошаговая инструкция

Настройка системы состоит из трёх простых шагов: подготовка среды, создание скрипта и его автоматический запуск.

Что потребуется

  • Клиентский компьютер: Любое устройство под управлением Linux (Raspberry Pi, домашний сервер, VPS).
  • Необходимое ПО:
    • iperf3: Утилита для тестирования.
    • NodeJS: Среда для запуска скрипта.
    • PM2: Менеджер процессов для автозапуска.

Шаг 1: Настройка среды

На машине, которая будет выполнять тесты, установим всё необходимое.

Установка NodeJS через NVM (рекомендуется)

Подробная документация: https://nodejs.org

  1. Установите NVM:
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
  2. Активируйте NVM (без перезахода в систему):
    \. "$HOME/.nvm/nvm.sh"
  3. Установите последнюю версию Node.js:
    nvm install 24
  4. Проверьте установку:
    node -v
    npm -v

Установка iperf3

sudo apt update
sudo apt install iperf3 -y

Шаг 2: Создание и настройка скрипта

  1. Создайте директорию для проекта:

    mkdir viziot_iperf3 && cd viziot_iperf3
  2. Инициализируйте проект и установите зависимости:

    npm init -y
    npm install viziot-mqtt-client-nodejs
  3. Включите поддержку ES-модулей: Откройте файл package.json и добавьте строку "type": "module",.

  4. Создайте основной файл скрипта:

    nano main.js
  5. Вставьте в него следующий код. Не забудьте указать ваши ключ и пароль от устройства VizIoT. В качестве цели для теста мы будем использовать один из общедоступных серверов iperf3.

import VizIoTMQTT from 'viziot-mqtt-client-nodejs'
import { spawn } from 'child_process'

// ===================================
// ========== НАСТРОЙКИ ==============
// ===================================

// 1. Введите ключ и пароль вашего устройства VizIoT
const keyDevice = '________________';
const passDevice = '____________________';

// 2. Установите интервал запуска тестов (сейчас - раз в час)
const intervalTime = 1000 * 60 * 60; // 1 час в миллисекундах

// 3. Настройте список серверов для тестирования.
const servers = [
    {
        // Пример: Тестирование до публичного сервера в Болгарии
        name: 'BG_Sofia',
        command: '-c 37.19.203.1',
    }
];

// --- Остальная часть кода универсальна и не требует изменений ---

const MAX_RETRIES = 3;
const RETRY_DELAY_MS = 30 * 1000;
const IPERF_TIMEOUT_MS = 60 * 1000;

const objMQTTClient = new VizIoTMQTT(keyDevice, passDevice);
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

function runCommand(command, args, timeoutMs) {
    return new Promise((resolve) => {
        const child = spawn(command, args, { timeout: timeoutMs });
        let stdout = '', stderr = '', timedOut = false;
        child.stdout.on('data', (data) => (stdout += data.toString()));
        child.stderr.on('data', (data) => (stderr += data.toString()));
        child.on('error', (err) => (stderr += `\nНе удалось запустить подпроцесс: ${err.message}`));
        child.on('close', (code, signal) => {
            if (signal === 'SIGTERM') {
                timedOut = true;
                stderr += '\nПроцесс был завершен по таймауту.';
            }
            resolve({ stdout, stderr, code, timedOut });
        });
    });
}

async function runIperfTest(iperfPath, serverCommand, testMode) {
    const testType = testMode.charAt(0).toUpperCase() + testMode.slice(1);
    const args = serverCommand.trim().split(' ');
    args.push('-J'); // JSON-вывод
    if (testMode === 'download') args.push('-R');
    else if (testMode === 'bidir') args.push('--bidir');

    for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
        console.log(`[ИНФО] Запускаем тест: ${testType} для ${serverCommand.trim()}. Попытка ${attempt}/${MAX_RETRIES}...`);
        const { stdout, stderr, timedOut } = await runCommand(iperfPath, args, IPERF_TIMEOUT_MS);
        const errorResult = { upload: -1, download: -1 };
        if (timedOut) { console.error(`[ОШИБКА] Тест (${testType}) превысил таймаут.`); return errorResult; }
        if (!stdout) { console.error(`[КРИТ] Команда iperf3 не вернула результат. Stderr: ${stderr.trim()}`); return errorResult; }
        try {
            const result = JSON.parse(stdout);
            if (result.error) {
                if (result.error.includes('the server is busy')) {
                    console.warn(`[ПРЕД] Сервер занят. Попытка ${attempt} не удалась.`);
                    if (attempt < MAX_RETRIES) { await delay(RETRY_DELAY_MS); continue; }
                    else { console.error(`[ОШИБКА] Сервер занят после ${MAX_RETRIES} попыток.`); return errorResult; }
                } else { console.error(`[ОШИБКА] iperf3:`, result.error); return errorResult; }
            }
            const finalResult = { upload: -1, download: -1 };
            const summary = result.end;
            if (summary.sum_sent) finalResult.upload = parseFloat((summary.sum_sent.bits_per_second / 1000000).toFixed(2));
            if (summary.sum_received) finalResult.download = parseFloat((summary.sum_received.bits_per_second / 1000000).toFixed(2));
            console.log(`[УСПЕХ] Результат (${testType}): Отдача: ${finalResult.upload} Мбит/с, Загрузка: ${finalResult.download} Мбит/с`);
            return finalResult;
        } catch (parseError) { console.error(`[КРИТ] Не удалось разобрать JSON-ответ от iperf3. Ответ:`, stdout); return errorResult; }
    }
    return { upload: -1, download: -1 };
}

async function getPacketAndSendToServer() {
    const results = {};
    for (const server of servers) {
        console.log(`\n--- Начинаем серию тестов для сервера: ${server.name} ---`);
        const uploadResult = await runIperfTest('iperf3', server.command, 'upload');
        results[`${server.name}_upload`] = uploadResult.upload;
        const downloadResult = await runIperfTest('iperf3', server.command, 'download');
        results[`${server.name}_download`] = downloadResult.download;
        const bidirResult = await runIperfTest('iperf3', server.command, 'bidir');
        results[`${server.name}_bidir_upload`] = bidirResult.upload;
        results[`${server.name}_bidir_download`] = bidirResult.download;
    }
    console.log('\n[УСПЕХ] Все тесты завершены. Итоговый пакет данных:', results);
    return results;
}

async function main() {
    console.log('[ИНФО] Скрипт запущен. Подключаемся к VizIoT и запускаем первый тест...');
    objMQTTClient.connect(() => console.log('[ИНФО] Успешное подключение к VizIoT MQTT.'));
    const initialPacket = await getPacketAndSendToServer();
    objMQTTClient.sendDataToVizIoT(initialPacket, (err) => {
        if (err) console.error(new Date(), 'ОШИБКА отправки начальных данных:', err);
        else console.log(new Date(), 'Начальные данные успешно отправлены.');
    });
    setInterval(async () => {
        console.log(`\n[ИНФО] Запускаем плановый тест (интервал: ${intervalTime / 1000} секунд)...`);
        const packet = await getPacketAndSendToServer();
        objMQTTClient.sendDataToVizIoT(packet, (err) => {
            if (err) console.error(new Date(), 'ОШИБКА отправки данных по интервалу:', err);
            else console.log(new Date(), 'Данные по интервалу успешно отправлены.');
        });
    }, intervalTime);
}

main();

Шаг 3: Автоматический запуск с помощью PM2

Чтобы скрипт работал 24/7, используем менеджер процессов PM2.

  1. Установите PM2 глобально: npm install pm2 -g
  2. Запустите скрипт: pm2 start main.js --name viziot_iperf3
  3. Настройте автозапуск PM2: pm2 startup (и выполните команду, которую он предложит)
  4. Сохраните список процессов: pm2 save

Полезные команды PM2:

  • pm2 list: Показать список запущенных процессов.
  • pm2 logs viziot_iperf3: Смотреть логи.
  • pm2 restart viziot_iperf3: Перезапустить.

Что дальше? Расширяем мониторинг

Теперь, когда у вас есть рабочая система, её легко можно улучшить.

Добавление собственного сервера (рекомендуется)

Для максимальной точности лучше тестировать до сервера, который вы контролируете (например, VPS или компьютер в локальной сети).

  1. На серверной машине:

    sudo apt update && sudo apt install iperf3 -y
    sudo ufw allow 5201/tcp # Открыть порт в брандмауэре

    (Согласитесь на запуск iperf3 в режиме сервиса)

  2. На клиентской машине: откройте main.js и добавьте ваш сервер в список.

    const servers = [
        {
            name: 'BG_Sofia', // Публичный сервер
            command: '-c 37.19.203.1',
        },
        {
            name: 'LOCAL_SERVER', // Ваш сервер
            command: '-c 192.168.0.100', // Укажите IP вашего сервера
        }
    ];
  3. Перезапустите скрипт: pm2 restart viziot_iperf3.

Теперь на вашей панели появятся графики скорости до вашего личного сервера.

Визуализация в VizIoT

После запуска данные начнут поступать в ваше устройство. Зайдите в VizIoT, создайте панель и добавьте виджеты.

  • Тип "График": Идеально подходит для отслеживания динамики ..._upload и ..._download.
  • Тип "Спидометр" (Gauge): Можно использовать для отображения последних результатов тестов.

Экспериментируйте, чтобы создать панель, которая будет максимально информативной именно для вас.