Python Internet Speed Test

I have been working remotely for a while now, and every time I go to a new place I perform an internet speed test. I need to know if the internet speed is high enough for me to have video calls. Many different websites already exist such as fast.com, speedtest.net, and speedcheck.org. A few weeks ago I started to think, how do these websites actually measure your internet speed? And more importantly, what do these different metrics actually mean. In this article, I will explain to you how a basic internet speed test works and how you can create an internet speed test using Python.

Internet Speed Test

Every time you do a speed test on one of these aforementioned websites, you are loading a file from a server. Ideally, this server is located close to you, as you can imagine that the further a server is physically located from your device, the longer it takes to load a file. This is essential as your internet speed is based on the total time it takes you to download that file. These websites know the exact size of that file and can calculate your speed with the following formula: S = A : T

Internet Speed Formula: S = A : T

This formula is super simple so I won’t take any time explaining it. The most important thing you need to know about this formula is that the result will be in Mbps. All of these websites that I have mentioned before will show your internet speed in Mbps. I always thought this meant Megabytes per second like if you would have a file of 1 Megabyte, it would take me 1 second to download it. However, this is not the case! Mbps means Megabits per second. 1 Byte is actually 8 bits (read this website for more info). This means that it will take you 8 seconds to download a file of 1 Megabyte with a speed of 1 Mbps (1 Megabit per second).

Bytes and bits. Megabits per second and Megabytes per second

As you will learn later in this article, these websites will actually divide a file into multiple chunks. Then it will take the average speed for all these different chunks to calculate your internet speed. This is why it takes a few seconds do an internet speed test, while you might be only downloading 1 MB (megabyte) of data.

Metrics

So amazing, you have just performed an internet speed test and you have gotten the following metrics:

  • Download Speed (Mbps)
  • Upload Speed (Mbps)
  • Ping (ms)

Download Speed and Upload Speed

I have already explained Download and Upload Speed in the previous paragraph. Divide whatever number you have gotten with 8 and you can calculate how long it will take to download a file if you know its size.

Ping (ms)

I haven’t discussed Ping yet. But this is actually one of the most important metric for me, as I do a lot of video calls. Ping will tell you something about the latency of your connection, in other words how long it takes for you to send a request to a server plus the time it takes for the server’s response to come back. Reason that this is so important for video calling is that you are streaming data from a server, but you are not able to buffer anything. You might know the word buffering from watching a video. Whenever you are watching a video you are downloading a file while you are loading it. If your internet speed is fast enough, but not stable enough, you shouldn’t experience any problems.

However, whenever your ping is high this means your internet speed is unstable. When video calling you can not compensate for this with a fast internet speed, as there is nothing to buffer yet. Everything happens in real-time and you need to load the frames in real-time. So if your ping is high, you will experience issues with video calling.

How to do an internet speed test with Python without modules

So before I show you the easiest way of doing an internet speed test with Python, I will show you how you will do this without importing a module. I think this will improve your understanding of how an internet speed test works. As you can see in the code below, we are loading a file with a certain size (1MB). We are then splitting this file into 1024 bits (128 bytes). As discussed previously, we take the average time it took per chunk of file to determine the total speed test.

def speed_test(size=5, ipv="ipv4", port=80):
    import sys, time, io, requests
    if size == 1024:
        size = "1GB"
    else:
        size = f"{size}MB"

    url = f"http://{ipv}.download.thinkbroadband.com:{port}/{size}.zip"

    with io.BytesIO() as f:
        start = time.perf_counter()
        r = requests.get(url, stream=True)
        total_length = r.headers.get('content-length')
        dl = 0
        if total_length is None: # no content length header
            f.write(r.content)
        else:
            for chunk in r.iter_content(1024):
                dl += len(chunk)
                f.write(chunk)
                done = int(30 * dl / int(total_length))
                sys.stdout.write("\r[%s%s] %s Mbps" % ('=' * done, ' ' * (30-done), dl//(time.perf_counter() - start) / 100000))

    print( f"\n{size} = {(time.perf_counter() - start):.2f} seconds")

speed_test(1)

How to measure Ping with Python without a module

To measure the ping (latency) of your internet speed, we can send a really small file to a server and wait for its response. We will do this multiple times as well, and get the average time to determine our ping.

import subprocess

def ping(server='example.com', count=1, wait_sec=1):
    """

    :rtype: dict or None
    """
    cmd = "ping -c {} -W {} {}".format(count, wait_sec, server).split(' ')
    try:
        output = subprocess.check_output(cmd).decode().strip()
        lines = output.split("\n")
        total = lines[-2].split(',')[3].split()[1]
        loss = lines[-2].split(',')[2].split()[0]
        timing = lines[-1].split()[3].split('/')
        return {
            'type': 'rtt',
            'min': timing[0],
            'avg': timing[1],
            'max': timing[2],
            'mdev': timing[3],
            'total': total,
            'loss': loss,
        }
    except Exception as e:
        print(e)
        return None


ping(server="google.com")

How to do an internet speed test with Python (Speedtest-cli)

The easiest way of doing an internet speed test with Python is using the module speedtest-cli

pip install speedtest-cli

In the code below you can see the internet speed with Python. The function test() contains the actual speed test and is normally sufficient. The extra code in the main() function is just to get a nice output for all your speedtest. Note that this speed test is more accurate as you are first selecting the best server and then loading the file from that server. Like I said, the further the server, the longer it will take for you to download the file.

import speedtest


def test():
    s = speedtest.Speedtest()
    s.get_servers()
    s.get_best_server()
    s.download()
    s.upload()
    res = s.results.dict()
    return res["download"], res["upload"], res["ping"]


def main():
    # write to csv
    with open('file.csv', 'w') as f:
        f.write('download,upload,ping\n')
        for i in range(3):
            print('Making test #{}'.format(i+1))
            d, u, p = test()
            f.write('{},{},{}\n'.format(d, u, p))
    # pretty write to txt file
    with open('file.txt', 'w') as f:
        for i in range(3):
            print('Making test #{}'.format(i+1))
            d, u, p = test()
            f.write('Test #{}\n'.format(i+1))
            f.write('Download: {:.2f} Kb/s\n'.format(d / 1024))
            f.write('Upload: {:.2f} Kb/s\n'.format(u / 1024))
            f.write('Ping: {}\n'.format(p))
    # simply print in needed format if you want to use pipe-style: python script.py > file
    for i in range(3):
        d, u, p = test()
        print('Test #{}\n'.format(i+1))
        print('Download: {:.2f} Kb/s\n'.format(d / 1024))
        print('Upload: {:.2f} Kb/s\n'.format(u / 1024))
        print('Ping: {}\n'.format(p))


if __name__ == '__main__':
    main()

How to measure ping using Python (Pingpython)

Of course there is an easier way of measuring the ping of your internet speed. This involves using a module called pingpython

pip install pingpython

The code to measure the ping using Python is really straightforward. Again, we are taking multiple measurements and use the average of those to determine our ping. In this example, we are pinging two different servers to get a more accurate result.


from pythonping import ping

def ping_host(host):
    ping_result = ping(target=host, count=10, timeout=2)

    return {
        'host': host,
        'avg_latency': ping_result.rtt_avg_ms,
        'min_latency': ping_result.rtt_min_ms,
        'max_latency': ping_result.rtt_max_ms,
        'packet_loss': ping_result.packet_loss
    }

hosts = [
    '192.168.48.1',
    '192.168.48.135'
]

for host in hosts:
    print(ping_host(host))

I hope you enjoyed learning about how to do a speed test in Python. If you are completely new, check out my article about installing Python with Anaconda. If you have any questions, do not hesitate to contact me.

Leave a Comment

Your email address will not be published. Required fields are marked *