Pomiar rzeczywistej przepustowości łącza internetowego – narzędzia skryptowe

speed_testPomiar rzeczywistej przepustowości łączy do Internetu przydaje się nie tylko wtedy, gdy chcemy wygrać spór z nieuczciwym dostawcą usług dostępowych. Może przydać się również – a może przede wszystkim – w bardziej pokojowych okolicznościach, na przykład do szeroko pojętej diagnostyki problemów w sieci. Możemy przykładowo badać „wąskie gardła” sieci, identyfikując problemy z przepustowością i czasem odpowiedzi.

Narzędzie, które opracowałem bazuje na oprogramowaniu speedtest, które trzeba zainstalować na komputerze z interpreterem języka Python. Można to uczynić poleceniem:

pip install speedtest

Należy również doinstalować w analogiczny sposób wszystkie niestandardowe moduły przywoływane w kodzie skryptu dyrektywami import, a wśród nich na pewno ‚optparse‚ (do kontroli składni i obsługi parametrów wywołania skryptu) oraz ‚xlwt‚ (do tworzenia i zapisywania danych do arkuszy kalkulacyjnych Excela, nawet jeśli Excelem nie dysponujemy) oraz ‚sched‚ (implementujący funkcje schedulera).

Sposób uruchomienia i działanie widać na poniższym przykładzie:

$ python speed_testing.py -h
Usage:
      _____       _                       _
     |_   _|     | |                     | |
       | |  _ __ | |_ ___ _ __ _ __   ___| |_
       | | | '_ \| __/ _ \ '__| '_ \ / _ \ __|
      _| |_| | | | ||  __/ |  | | | |  __/ |_
     |_____|_| |_|\__\___|_|  |_|_|_|\___|\__|    _   _
      / ____|                   | | | |          | | (_)
     | (___  _ __   ___  ___  __| | | |_ ___  ___| |_ _ _ __   __ _
      \___ \| '_ \ / _ \/ _ \/ _` | | __/ _ \/ __| __| | '_ \ / _` |
      ____) | |_) |  __/  __/ (_| | | ||  __/\__ \ |_| | | | | (_| |
     |_____/| .__/ \___|\___|\__,_|  \__\___||___/\__|_|_| |_|\__, |
            | |                                                __/ |
            |_| =========== Janusz Nawrat - 2015 ============ |___/


Options:
  -h, --help            show this help message and exit
  -s NO_SAMPLE, --samples=NO_SAMPLE
                        Number of samples
  -t TIME_SAMLPLE, --time_of_sampling=TIME_SAMLPLE
                        Time of sampling in seconds

$ python speed_testing.py -s 20 -t 60

      _____       _                       _
     |_   _|     | |                     | |
       | |  _ __ | |_ ___ _ __ _ __   ___| |_
       | | | '_ \| __/ _ \ '__| '_ \ / _ \ __|
      _| |_| | | | ||  __/ |  | | | |  __/ |_
     |_____|_| |_|\__\___|_|  |_|_|_|\___|\__|    _   _
      / ____|                   | | | |          | | (_)
     | (___  _ __   ___  ___  __| | | |_ ___  ___| |_ _ _ __   __ _
      \___ \| '_ \ / _ \/ _ \/ _` | | __/ _ \/ __| __| | '_ \ / _` |
      ____) | |_) |  __/  __/ (_| | | ||  __/\__ \ |_| | | | | (_| |
     |_____/| .__/ \___|\___|\__,_|  \__\___||___/\__|_|_| |_|\__, |
            | |                                                __/ |
            |_| =========== Janusz Nawrat - 2015 ============ |___/

[*] START: 2015-11-07 15:16:44.333000
[*] Testing in progress...
[+] Pomiar: 00, czas: 2015-11-07 15:17:42.876000, Download: 1.76 Mbit/s
[+] Pomiar: 01, czas: 2015-11-07 15:20:39.877000, Download: 2.01 Mbit/s
[+] Pomiar: 02, czas: 2015-11-07 15:23:37.403000, Download: 2.02 Mbit/s
[+] Pomiar: 03, czas: 2015-11-07 15:26:20.620000, Download: 1.87 Mbit/s
[+] Pomiar: 04, czas: 2015-11-07 15:29:13.463000, Download: 1.79 Mbit/s
[+] Pomiar: 05, czas: 2015-11-07 15:32:18.168000, Download: 1.98 Mbit/s
...
[>] Do you want to extract data do Excel spreadsheet (Y/N)? y
[*] Data extraction started
 1 ; 2015-11-07 15:17:42 ; 1.76 ; 68.145
 2 ; 2015-11-07 15:20:39 ; 2.01 ; 44.712
 3 ; 2015-11-07 15:23:37 ; 2.02 ; 44.823
 4 ; 2015-11-07 15:26:20 ; 1.87 ; 836.417
 5 ; 2015-11-07 15:29:13 ; 1.79 ; 2240.205
...
[*] Results saved also to speedtest_results.xls spreadsheet file

Skrypt uruchamia w określonym parametrem -t cyklu (czas trwania cyklu) procedury pomiaru pasma łącza. Parametrem -s z kolei określona jest liczba cykli składających się na pomiar. Przy pomocy wyrażeń regularnych skrypt w następnym kroku wydobywa z danych wyjściowych tych procedur informacje na temat przepustowości i opóźnienia w czasie odpowiedzi sieci. Te dane zapisuje potem do pliku tekstowego, którego nazwę określa globalna zmienna programu REPORT_FILE. Na koniec pomiaru, w odpowiedzi na monit programu, użytkownik może wyrazić swoja wolę, by zgromadzone dane zapisać także do arkusza kalkulacyjnego w formacie MS Excel.

Skrypt w aktualnej postaci pozyskuje dane na temat przepustowości łącza wyłącznie dla strumienia przychodzącego (downstream transfer), ale nic nie stoi na przeszkodzie, by zmodyfikować go lekko, aby pobierał dane o przepustowości łącza także przy wysyłaniu danych (upstream transfer) do sieci. Te dwie wielkości na pewno będą się istotnie różnić w przypadku łączy z transferem asymetrycznym (na przykład ADSL).

Wspomniana modyfikacja polegałaby na „łapaniu” wielkości wskazującej na ‚upload speed’:

if 'Upload' in line:
    pom += 1
    result = re.sub(r'(^.+?)(\d+.\d+)(.*)', '\g', line)
    print "%2d ; %s ; %s ; %s" % (pom, data, result, opoznienie)
    sheet1.write(pom-1, 0, pom); sheet1.write(pom-1, 1, data); sheet1.write(pom-1, 2, float(result))
    sheet1.write(pom-1, 3, float(opoznienie))

Wspomniany eksport danych do arkusza kalkulacyjnego może służyć różnym celom, na przykład wizualizacji danych, i choć Python posiada dużo własnych tego rodzaju specjalistycznych bibliotek, to Excel wydaje się czasem być najprostszym z istniejących rozwiązań.

Pa przykład można pokusić się o wykreślenie wyników pomiaru w postaci następującego diagramu.

wykres
Kod źródłowy skryptu jest tu:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sched, re
import time, sys, datetime
import subprocess
from optparse import OptionParser
from xlwt import Workbook

REPORT_FILE = 'speed_report.txt'
WORKSHEET = 'speedtest_results.xls'

def pomiar(id):
    try: 
        proc = subprocess.Popen(['speedtest'], stdout=subprocess.PIPE)
    except:
        print >> sys.stderr, "[!] No speedtest module installed: run 'pip install speedtest'"
        sys.exit(1)
    output = proc.stdout.read()
    speed = re.search(r'(Download:.+)', output)
    try: 
        f = open(REPORT_FILE,'a')
    except:
        print >> sys.stderr, "[!] Problem with opening %s file" % REPORT_FILE
        sys.exit(1)
    
    spd = ""
    if speed:
        spd = speed.group()
    
    print "[+] Pomiar: %02d, czas: %s, %s" % (int(id), datetime.datetime.now(), spd)
    czas = datetime.datetime.now()
    f.write("%s\n" % czas)
    f.write(output)
    f.close()
# end of pomiar()
    
def extract_data_to_excel():
    try:
        book = Workbook()
        sheet1 = book.add_sheet('Pomiary')
    except:
        print >> sys.stderr, "[!] Problem with spreadsheet workbook creation"
        sys.exit(1)

    try:
        with open(REPORT_FILE) as f:
            content = f.readlines()
    except:
        print >> sys.stderr, "[!] Problem with %s file opening" % REPORT_FILE
        sys.exit(1)
        
    print >> sys.stderr, "[*] Data extraction started"
    pom = 0    
    for line in content:
        line = re.sub('\n', '', line)
        date_and_time = re.search(r'(^\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})', line)
        
        if date_and_time:
            data = date_and_time.group()
        latency = re.search(r'^Hosted by.+?\[(\d+\.\d+\s+km)\]:.+?(\d+\.\d*).+', line)
        
        if latency:
            # print "[+] Latency: %s" % latency.group(2)
            opoznienie = latency.group(2)
        
        if 'Download' in line:
            pom += 1
            result = re.sub(r'(^.+?)(\d+.\d+)(.*)', '\g', line)
            print "%2d ; %s ; %s ; %s" % (pom, data, result, opoznienie)
            sheet1.write(pom-1, 0, pom); sheet1.write(pom-1, 1, data); sheet1.write(pom-1, 2, float(result))
            sheet1.write(pom-1, 3, float(opoznienie))        
    try:
        book.save(WORKSHEET)    
        print >> sys.stderr, "[*] Results saved also to %s spreadsheet file" % WORKSHEET
    except:
        print >> sys.stderr, "[!] Problem with saving data to %s spreadsheet file" % WORKSHEET
        sys.exit(1)
# end of extract_data_to_excel()
        
if __name__ == "__main__":    

    scheduler = sched.scheduler(time.time, time.sleep)
    usage = u"""
      _____       _                       _                         
     |_   _|     | |                     | |                        
       | |  _ __ | |_ ___ _ __ _ __   ___| |_                       
       | | | '_ \| __/ _ \ '__| '_ \ / _ \ __|                      
      _| |_| | | | ||  __/ |  | | | |  __/ |_                       
     |_____|_| |_|\__\___|_|  |_|_|_|\___|\__|    _   _             
      / ____|                   | | | |          | | (_)            
     | (___  _ __   ___  ___  __| | | |_ ___  ___| |_ _ _ __   __ _ 
      \___ \| '_ \ / _ \/ _ \/ _` | | __/ _ \/ __| __| | '_ \ / _` |
      ____) | |_) |  __/  __/ (_| | | ||  __/\__ \ |_| | | | | (_| |
     |_____/| .__/ \___|\___|\__,_|  \__\___||___/\__|_|_| |_|\__, |
            | |                                                __/ |
            |_| =========== Janusz Nawrat - 2015 ============ |___/ 
    """
    parser = OptionParser(usage=usage)
    
    parser.add_option('-s', '--samples', type='int',
                      help='Number of samples',
                      dest='no_sample', default=0)
                      
    parser.add_option('-t', '--time_of_sampling', type='int',
                      help='Time of sampling in seconds',
                      dest='time_samlple', default=0)
    
    options, args = parser.parse_args()

    if options.no_sample:
        nums = options.no_sample
    else:
        nums = int(raw_input("[>] Number of samples: "))
    
    if options.time_samlple:
        tms = options.time_samlple
    else:
        tms = int(raw_input("[>] Sampling time in seconds: "))
    
    print usage
    # parser.print_help()

    print '[*] START:', datetime.datetime.now()
    print "[*] Testing in progress..."

    for i in range(0,nums-1):
        scheduler.enter(i*tms, 1, pomiar, ('%d' % i,))

    scheduler.run()
    
    if (raw_input("[>] Do you want to extract data do Excel spreadsheet (Y/N)? ").upper()) == 'Y':
        extract_data_to_excel()

Życzę Wam dobrej zabawy z kodem. Mam nadzieję, że skrypt przyda się „sieciowcom”, do grona których mam przyjemność także należeć.

Reklamy

Informacje Janusz Nawrat
Just ordinary man who likes thinking...

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s

TOMASZ WEŁNA

artysta grafik | wykładowca

PRACOWNIA OKO

Szkoła Rysunku Malarstwa i Grafiki DR TOMASZA WEŁNY | KRAKÓW | Plac Matejki 10 | tel 691 81 75 74

Piękno neurobiologii

Blog Jerzego Vetulaniego

Teoria muzyki, zasady muzyki, podstawy muzyki

Teoria muzyki, zasady muzyki, podstawy muzyki - czyli to co każdy amator muzyki wiedzieć powinien :)

Personal Development & Inspirations

Przemyślenia i refleksje, którymi warto się podzielić (blog by Janusz Nawrat)

Business IT Cooperation Platform

Biznes i IT - dwa światy, które muszą współdziałać

%d blogerów lubi to: