Загрузка данных


# 1. Полный обход ошибок SSL/TLS и сертификатов
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

$logPath = "$env:USERPROFILE\Desktop\network_6hours_test.txt"
$stats = @{}

# Исключительно легитимные и доступные в РФ ресурсы (DNS, CDN, медиа, ритейл)
$targets = @(
    # Публичные DNS (надежный базовый тест связности)
    '8.8.8.8', '1.1.1.1', '77.88.8.8',
    
    # Крупнейшие отечественные экосистемы и сервисы
    'yandex.ru', 'vk.com', 'mail.ru', 'dzen.ru', 'rutube.ru', 'ok.ru', '2gis.ru', 'kinopoisk.ru',
    
    # Торговые площадки и ритейл (с префиксом www для корректного SSL)
    'www.ozon.ru', 'www.wildberries.ru', 'www.avito.ru', 'dns-shop.ru', 'citilink.ru',
    
    # Провайдеры и инфраструктурные узлы
    'mts.ru', 'megafon.ru', 'beeline.ru', 'rostelecom.ru', 'selectel.ru'
)

foreach ($t in $targets) {
    $stats[$t] = [PSCustomObject]@{ Sent = 0; Lost = 0; Times = [System.Collections.Generic.List[int]]::new() }
}

$startTime = Get-Date
$durationHours = 6
$endTime = $startTime.AddHours($durationHours)
$speeds = [System.Collections.Generic.List[double]]::new()

Write-Host "ТЕСТ ЗАПУЩЕН НА $durationHours ЧАСОВ (до $($endTime.ToString('HH:mm:ss')))" -ForegroundColor Cyan
Write-Host "Лог сохранится на Рабочий стол: $logPath`n" -ForegroundColor Yellow

while ((Get-Date) -lt $endTime) {
    $now = Get-Date -Format 'HH:mm:ss'
    
    # Замер чистой скорости через нейтральный CDN Selectel
    $speedMbps = 0
    $swSpeed = [System.Diagnostics.Stopwatch]::StartNew()
    try {
        $wc = New-Object System.Net.WebClient
        $data = $wc.DownloadData("https://speedtest.selectel.ru/10MB")
        $swSpeed.Stop()
        if ($swSpeed.ElapsedMilliseconds -gt 0) {
            $speedMbps = [math]::Round((($data.Length * 8) / 1000000) / ($swSpeed.ElapsedMilliseconds / 1000), 2)
            $speeds.Add($speedMbps)
        }
    } catch { $swSpeed.Stop() }

    Write-Host "=== ОПРОС [$now] | СКОРОСТЬ КАНАЛА: $speedMbps Мбит/с ===" -ForegroundColor Cyan

    foreach ($target in $targets) {
        $item = $stats[$target]
        $url = if ($target -match '^\d+\.\d+\.\d+\.\d+$') { "http://$target" } else { "https://$target" }
        
        $currentLost = 0
        $currentTimes = @()

        for ($i = 0; $i -lt 3; $i++) {
            $item.Sent++
            $sw = [System.Diagnostics.Stopwatch]::StartNew()
            try {
                $req = [System.Net.HttpWebRequest]::Create($url)
                $req.Timeout = 2500
                $req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
                $req.Method = "GET"
                $req.AllowAutoRedirect = $false

                $resp = $req.GetResponse()
                $sw.Stop()
                
                $lat = [int]$sw.ElapsedMilliseconds
                $item.Times.Add($lat)
                $currentTimes += $lat
                $resp.Close()
            }
            catch [System.Net.WebException] {
                $sw.Stop()
                # Если сервер вернул Любой ответ (даже 301, 302, 403, SSL-Warning) — узел ДОСТУПЕН, потерь НЕТ
                if ($_.Response -or $_.Status -eq [System.Net.WebExceptionStatus]::TrustFailure -or $_.Status -eq [System.Net.WebExceptionStatus]::SecureChannelFailure) {
                    $lat = [int]$sw.ElapsedMilliseconds
                    if ($lat -gt 0) { $item.Times.Add($lat); $currentTimes += $lat }
                    if ($_.Response) { $_.Response.Close() }
                } else {
                    # Реальный таймаут или обрыв физического соединения
                    $item.Lost++
                    $currentLost++
                }
            }
            catch {
                $sw.Stop()
                $item.Lost++
                $currentLost++
            }
        }

        $lossPerc = [math]::Round(($currentLost / 3) * 100)
        $avgLat = if ($currentTimes.Count -gt 0) { [math]::Round(($currentTimes | Measure-Object -Average).Average) } else { 0 }

        if ($lossPerc -eq 100) {
            Write-Host "[$now] $($target,-20) : Loss = 100% | TIMEOUT / DROPPED" -ForegroundColor Red
        } elseif ($lossPerc -gt 0) {
            Write-Host "[$now] $($target,-20) : Loss = $lossPerc% | Latency = ${avgLat}ms" -ForegroundColor Yellow
        } else {
            Write-Host "[$now] $($target,-20) : Loss = 0% | Latency = ${avgLat}ms" -ForegroundColor Green
        }
    }

    Start-Sleep -Seconds 3
}

# --- ФОРМИРОВАНИЕ ФИНАЛЬНОГО ОТЧЕТА ПО ИСТЕЧЕНИИ 6 ЧАСОВ ---
$finishTime = Get-Date
$avgTotalSpeed = if ($speeds.Count -gt 0) { [math]::Round(($speeds | Measure-Object -Average).Average, 2) } else { 0 }

$report = @()
$report += "========================================================================="
$report += "               ИТОГОВЫЙ ОТЧЕТ ТЕСТИРОВАНИЯ СВЯЗИ (6 ЧАСОВ)               "
$report += "========================================================================="
$report += "Начало теста:      $($startTime.ToString('yyyy-MM-dd HH:mm:ss'))"
$report += "Завершение теста:  $($finishTime.ToString('yyyy-MM-dd HH:mm:ss'))"
$report += "Средняя скорость канала: $avgTotalSpeed Мбит/с"
$report += "=========================================================================`n"
$report += String::Format("{0,-22} | {1,-18} | {2,-20}", "Сервис / Узел", "Потери пакетов %", "Задержка (avg/max ms)")
$report += "-------------------------------------------------------------------------"

foreach ($target in ($targets | Sort-Object)) {
    $item = $stats[$target]
    $total = $item.Sent
    $lost = $item.Lost
    $totalLossPerc = if ($total -gt 0) { [math]::Round(($lost / $total) * 100, 1) } else { 0 }
    
    $avgLat = if ($item.Times.Count -gt 0) { [math]::Round(($item.Times | Measure-Object -Average).Average) } else { 0 }
    $maxLat = if ($item.Times.Count -gt 0) { ($item.Times | Measure-Object -Maximum).Maximum } else { 0 }

    $report += String::Format("{0,-22} | {1,5}% ({2,4}/{3,-4}) | {4,5} / {5,-5} ms", $target, $totalLossPerc, $lost, $total, $avgLat, $maxLat)
}

$report | Out-File -FilePath $logPath -Encoding utf8
Write-Host "`nТЕСТ УСПЕШНО ЗАВЕРШЕН. Итоговый отчет сохранен в файл: $logPath" -ForegroundColor Green