Rehber Python ile Download Speedtest yapmak

Merhaba arkadaşlar, öncelikle belirteyim upload kodları da hazır ancak konusunu yazmaya üşendiğim için farklı bir gün paylaşırım diye düşünüyorum.

Bu yazıyı yazmaya nasıl karar verdiğimden bahsedeyim öncelikle. Instagram, YouTube gibi yerlerde gezinirken çoğundan nefret ettiğim "programming influencer" diye adlandırdığım oluşumların çoğunun ürettiği bir içerikti bu ve tek yaptıkları aslında speedtest.net'in hazır modülünü kullanıp print etmekti. Ne get isteğinden, ne HTTP'den ne de TCP'den haberleri vardı. Ya da download hızını ölçmenin mantığından hiç mi hiç bahsetmiyorlardı. Kısacası aslında hiçbir şey anlatmıyorlardı safi görüntüydü. Madem öyle dedim Türkiye'nin en büyük forumunda en azından merak eden arkadaşlar için "Başlangıç (Bu akıllardan çıkmasın)" düzeyinde temel olarak işin mantığını anlatan bir program yazalım hep birlikte. Tabii bu bilgiler benim bildiklerim eksik elbette ki olabilir.

Temel Mantığı Anlama
Aslında işin özü çok basit, bir sunucuya dersin ki ben senden dosya indirmek isitiyorum. O sunucu sana o dosyayı aktarır. Aktarma işlemi başladığındaki süreyi alırsın. Bittiğindeki süreyi alırsın. Dosya boyutu / Süre sana indirme hızını verir.

Program
İşi temel olarak anlamlandırdığımıza göre ufaktan kodu yazmaya başlayabiliriz.

Python:
#Programın temel görünüşü

#ana tanımlamalar

def main():
 ...

if __name__ == '__main__':
 main()

En temel düzenimizi belirledikten sonra şimdi ana değişkenlerimizi tanımlıyoruz. Bunlar bağlanacağımız sunucu ve port adresleri ancak ortada bir eksik var sunucumuz yok ki.

Speedtest için özel yapılandırılmış sunucular vardır. Bu sunucular ISS'lerin sağladığı sunucular da olabilir. Hız testi servislerinin sağladığı sunucular da olabilir. Araştırmalarım kadarıyla çoğu ISS download için sunucular sağlamakta. Bu adresten genel olarak doğru şekilde sunucu adresleri alabilirsiniz ancak Türkiye gibi ülkeler için eksik ve hatalı adresler var. Çünkü Ookla artık bu adresleri döndürmüyormuş(?). Bu yüzden ben de Firefox tarayıcısı üzerinden speedtest.net'in download testi için kullandığı serveri, geliştirici aracı üzerinden çektim ve bulduğum adreslerden biri şuydu http://speedtest2.vodafone.com.tr:8080/download bu sunucu İstanbul'da ya da İzmir TurkNet sunucusu speedtest35.turk.net:8080/download. Şimdilik sunucuları bulma işine pek girmeyeceğim.

Sunucuların yaptıkları iş ise tam olarak şu /download dosyası için get isteği atıyorsunuz ve size download dosyasını (10GB) aktarmaya başlıyor. Belli bir süre geçtikten sonra iptal ediyor ve yeniden atmaya başlıyor bu siz bağlantıyı kapatmadığınız sürece devam ediyor. Ancak tabii ki dosyayı hiçbir zaman indiremiyorsunuz sadece belirli sayıda veri alıyorsunuz. Tam da Speedtest için ihtiyacımız olan şey.

Şimdi GET isteği oluşturma, bağlantıyı oluşturma gibi kodlarımızı yazalım. Kullanacağımız kütüphaneleri içeri aktarıyoruz konunun başında da belirttiğim gibi mümkün olduğunca en az otomatik şekilde ilerleyeceğiz. Kullanacağımız kütüphaneler socket ve time kütüphaneleri.
Socket kütüphanesi internet üzerinden veri alışverişi yapmak için kullanılır. Time kütüphanesini ise adından da anlaşılacağı gibi zamanı tutmak için kullanacağız. Adresi, Portu ve atacağımız isteği belirliyoruz. Daha sonra soketi ve bağlantıyı oluşturuyoruz. Yorum satırlarını okumayı ihmal etmeyin.

Python:
import socket # socket kütüphanesi internet üzerinden veri alışverişi yapmak için kullanılır
import time # time kütüphanesi zaman işlemleri için kullanılır

#IP adresi ve Port numarasını tanımlıyoruz.
address = ('speedtest2.vodafone.com.tr', 8080) #Verinin bulunduğu IP adresi ve port numarası

#HTTP get isteğini tanımlıyoruz. Bu istekte /download'a istekte bulunuyoruz,
#ancak önemli olan bir diğer nokta User-Agent değeri çünkü istek attığımız sunucu,
#User-Agent yani tarayıcı kimliğimizi aktarmadan veri yollamayı reddediyor.
#GET istekleri daha fazla detaylandırabilir ancak şimdilik atlayacağız.
#Tabii ki veriyi byte olarak atıyoruz. Bu noktayı da artık siz araştırmalısınız.
GET_REQUEST = b"GET /download HTTP/1.1\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0\r\nConnection: keep-alive\r\n\r\n"

def main():
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #socket oluşturuyoruz.
 #bu AF_INET ve SOCK_STREAM neyin nesi daha sonra biraz açıklayacağım.
 sock.connect(address) # address değişkeninde tanımlı olan IP adresi ve port numarası ile sunucuya bağlantı kuruyoruz.

 print('Connected to', address) #Eğer program çökmediyse bir şeyler yazdıralım güzel gözüksün :D

 ...

Yorum satırlarında da bahsettiğim gibi nedir bu socket.AF_INET ve socket.SOCK_STREAM
socket.AF_INET (Address Family Internet) adres ailesi olarak geçer. Bu değer IPv4'ü temsil eder. Ve adresler arası iletişimi sağlar.
socket.SOCK_STREAM veri akışının TCP (Transmission Control Protocol) protokolünü kullanacağını belirtir. TCP, veri akışının güvenli ve hata düzeltme özellikleri olan bir protokoldür. Hatta bu protokol gerektiğinde veriyi tekrar ister ki hata olmasın.
Şimdi kodumuzun diğer kısımlarını yazalım. Yine yorum satırlarına dikkat edin.

Python:
...

# İndirme işlemi başlangıcının tarih ve saati
start = time.time()

sock.send(GET_REQUEST) # GET_REQUEST değişkeninde tanımlı olan HTTP GET isteğini sunucuya gönderelim

downloaded = 0 #İndirilen verinin miktarını tutan değişken

while True: #Yeni veri gelmeyene kadar veri almaya devam edeceğimiz için loop açıyoruz.
 resp = sock.recv(1 << 20) #sunucudan veri alınmasını teslim eder. "1<<20" alınan verinin byte cinsinden 1MB büyüklüğüdür buraya byte cinsinden herhangi bir değer yazılabilir ancak çok küçük veya çok büyük değerler yazılmamalı 1MB ideal.
 if not resp: #eğer yeni veri yoksa
 break #döngüden çık

 downloaded += len(resp) #Alınan verinin miktarı 'downloaded' değişkenine eklenir. Alınan veri byte cinsindendir. Ve verinin uzunluğu len(resp) verinin kaç byte olduğunu bize iletir.
 print('Downloaded', downloaded / (1024 * 1024), 'MB') # İndirilen verinin miktarının MB cinsinden ekrana yazdırılması. Byte to MB dönüşümü kullanıldı tabii ki.
 print((downloaded / (1024 * 1024)) / (time.time() - start) * 8, 'Mbps') #konunun başında belirttiğim işlemi gerçekleştirdik. Yine aynı şekilde Byte to MB dönüşümü kullandık ve MB/Sn cinsinden hızı bulduk ve 8 ile çarparak mbps cinsine çevirdik.

end = time.time() #indirme işleminin bitiş zamanı saniye cinsinden (Bu olayı araştırmanızı tavsiye ederim keyifli bir olay)
# İndirilen verinin miktarının MB cinsinden ekrana yazdırılması
print('Downloaded', downloaded / (1024 * 1024), 'MB')
# İndirme hızının Mbps cinsinden ekrana yazdırılması
print((downloaded / (1024 * 1024)) / (end - start) * 8, 'Mbps')

#en son tekrar yazdırdık ve bitti.

Kodun tam hali bu şekilde.

Python:
import socket
import time

address = ('speedtest2.vodafone.com.tr', 8080)

GET_REQUEST = b"GET /download HTTP/1.1\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0\r\nConnection: keep-alive\r\n\r\n"

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(address)
    print('Connected to', address)

    start = time.time()
    sock.send(GET_REQUEST)
    downloaded = 0
    while True:
        resp = sock.recv(1 << 20)
        if not resp:
            break
        downloaded += len(resp)
        print('Downloaded', downloaded / (1024 * 1024), 'MB')
        print((downloaded / (1024 * 1024)) / (time.time() - start) * 8, 'Mbps')
   
    end = time.time()

    print('Downloaded', downloaded / (1024 * 1024), 'MB')
    print((downloaded / (1024 * 1024)) / (end - start) * 8, 'Mbps')

if __name__ == '__main__':
    main()

Umarım en az şekilde hata yapmışımdır (Hatasız kul olmaz.) Ve umarım eğlenceli ve öğretici bir yazı olmuştur. "Programming Influencer"ların kökünün kuruması dileğiyle. Okuduğunuz için teşekkür ederim.
Unutmayın ki bu program güvenlik açıkları ve optimizasyon sıkıntıları barındırabilir ve profesyonel işlerce kullanılmasını tavsiye etmiyorum.
Bazı konuların bilerek yüzeysel geçildiğini ve araştırmaya teşvik için bunun yapıldığını unutmayın. Araştırın ve öğrenmeye çalışın her şey böyle başlar.

Kod bloklarında hata oluşmuş. Bazı ifadeler olmaması gereken yerlerde. Denemek isteyenler onları düzeltsinler mutlaka ya da kodun tamamı kısmından kopyalasın Yardıma ihtiyacı olanlar konu altına etiketlesin.
 
Son düzenleme:
Merhaba arkadaşlar, öncelikle belirteyim upload kodları da hazır ancak konusunu yazmaya üşendiğim için farklı bir gün paylaşırım diye düşünüyorum.

Bu yazıyı yazmaya nasıl karar verdiğimden bahsedeyim öncelikle. Instagram, YouTube gibi yerlerde gezinirken çoğundan nefret ettiğim "programming influencer" diye adlandırdığım oluşumların çoğunun ürettiği bir içerikti bu ve tek yaptıkları aslında speedtest.net'in hazır modülünü kullanıp print etmekti. Ne get isteğinden, ne HTTP'den ne de TCP'den haberleri vardı. Ya da download hızını ölçmenin mantığından hiç mi hiç bahsetmiyorlardı. Kısacası aslında hiçbir şey anlatmıyorlardı safi görüntüydü. Madem öyle dedim Türkiye'nin en büyük forumunda en azından merak eden arkadaşlar için "Başlangıç (Bu akıllardan çıkmasın)" düzeyinde temel olarak işin mantığını anlatan bir program yazalım hep birlikte. Tabii bu bilgiler benim bildiklerim eksik elbette ki olabilir.

Temel Mantığı Anlama
Aslında işin özü çok basit, bir sunucuya dersin ki ben senden dosya indirmek isitiyorum. O sunucu sana o dosyayı aktarır. Aktarma işlemi başladığındaki süreyi alırsın. Bittiğindeki süreyi alırsın. Dosya boyutu / Süre sana indirme hızını verir.

Program
İşi temel olarak anlamlandırdığımıza göre ufaktan kodu yazmaya başlayabiliriz.

Python:
#Programın temel görünüşü

#ana tanımlamalar

def main():
 ...

if __name__ == '__main__':
 main()

En temel düzenimizi belirledikten sonra şimdi ana değişkenlerimizi tanımlıyoruz. Bunlar bağlanacağımız sunucu ve port adresleri ancak ortada bir eksik var sunucumuz yok ki.

Speedtest için özel yapılandırılmış sunucular vardır. Bu sunucular ISS'lerin sağladığı sunucular da olabilir. Hız testi servislerinin sağladığı sunucular da olabilir. Araştırmalarım kadarıyla çoğu ISS download için sunucular sağlamakta. Bu adresten genel olarak doğru şekilde sunucu adresleri alabilirsiniz ancak Türkiye gibi ülkeler için eksik ve hatalı adresler var. Çünkü Ookla artık bu adresleri döndürmüyormuş(?). Bu yüzden ben de Firefox tarayıcısı üzerinden speedtest.net'in download testi için kullandığı serveri, geliştirici aracı üzerinden çektim ve bulduğum adreslerden biri şuydu http://speedtest2.vodafone.com.tr:8080/download bu sunucu İstanbul'da ya da İzmir TurkNet sunucusu speedtest35.turk.net:8080/download. Şimdilik sunucuları bulma işine pek girmeyeceğim.

Sunucuların yaptıkları iş ise tam olarak şu /download dosyası için get isteği atıyorsunuz ve size download dosyasını (10GB) aktarmaya başlıyor. Belli bir süre geçtikten sonra iptal ediyor ve yeniden atmaya başlıyor bu siz bağlantıyı kapatmadığınız sürece devam ediyor. Ancak tabii ki dosyayı hiçbir zaman indiremiyorsunuz sadece belirli sayıda veri alıyorsunuz. Tam da Speedtest için ihtiyacımız olan şey.

Şimdi GET isteği oluşturma, bağlantıyı oluşturma gibi kodlarımızı yazalım. Kullanacağımız kütüphaneleri içeri aktarıyoruz konunun başında da belirttiğim gibi mümkün olduğunca en az otomatik şekilde ilerleyeceğiz. Kullanacağımız kütüphaneler socket ve time kütüphaneleri.
Socket kütüphanesi internet üzerinden veri alışverişi yapmak için kullanılır. Time kütüphanesini ise adından da anlaşılacağı gibi zamanı tutmak için kullanacağız. Adresi, Portu ve atacağımız isteği belirliyoruz. Daha sonra soketi ve bağlantıyı oluşturuyoruz. Yorum satırlarını okumayı ihmal etmeyin.

Python:
import socket # socket kütüphanesi internet üzerinden veri alışverişi yapmak için kullanılır
import time # time kütüphanesi zaman işlemleri için kullanılır

#IP adresi ve Port numarasını tanımlıyoruz.
address = ('speedtest2.vodafone.com.tr', 8080) #Verinin bulunduğu IP adresi ve port numarası

#HTTP get isteğini tanımlıyoruz. Bu istekte /download'a istekte bulunuyoruz,
#ancak önemli olan bir diğer nokta User-Agent değeri çünkü istek attığımız sunucu,
#User-Agent yani tarayıcı kimliğimizi aktarmadan veri yollamayı reddediyor.
#GET istekleri daha fazla detaylandırabilir ancak şimdilik atlayacağız.
#Tabii ki veriyi byte olarak atıyoruz. Bu noktayı da artık siz araştırmalısınız.
GET_REQUEST = b"GET /download HTTP/1.1\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0\r\nConnection: keep-alive\r\n\r\n"

def main():
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #socket oluşturuyoruz.
 #bu AF_INET ve SOCK_STREAM neyin nesi daha sonra biraz açıklayacağım.
 sock.connect(address) # address değişkeninde tanımlı olan IP adresi ve port numarası ile sunucuya bağlantı kuruyoruz.

 print('Connected to', address) #Eğer program çökmediyse bir şeyler yazdıralım güzel gözüksün :D

 ...

Yorum satırlarında da bahsettiğim gibi nedir bu socket.AF_INET ve socket.SOCK_STREAM
socket.AF_INET (Address Family Internet) adres ailesi olarak geçer. Bu değer IPv4'ü temsil eder. Ve adresler arası iletişimi sağlar.
socket.SOCK_STREAM veri akışının TCP (Transmission Control Protocol) protokolünü kullanacağını belirtir. TCP, veri akışının güvenli ve hata düzeltme özellikleri olan bir protokoldür. Hatta bu protokol gerektiğinde veriyi tekrar ister ki hata olmasın.
Şimdi kodumuzun diğer kısımlarını yazalım. Yine yorum satırlarına dikkat edin.

Python:
...

# İndirme işlemi başlangıcının tarih ve saati
start = time.time()

sock.send(GET_REQUEST) # GET_REQUEST değişkeninde tanımlı olan HTTP GET isteğini sunucuya gönderelim

downloaded = 0 #İndirilen verinin miktarını tutan değişken

while True: #Yeni veri gelmeyene kadar veri almaya devam edeceğimiz için loop açıyoruz.
 resp = sock.recv(1 << 20) #sunucudan veri alınmasını teslim eder. "1<<20" alınan verinin byte cinsinden 1MB büyüklüğüdür buraya byte cinsinden herhangi bir değer yazılabilir ancak çok küçük veya çok büyük değerler yazılmamalı 1MB ideal.
 if not resp: #eğer yeni veri yoksa
 break #döngüden çık

 downloaded += len(resp) #Alınan verinin miktarı 'downloaded' değişkenine eklenir. Alınan veri byte cinsindendir. Ve verinin uzunluğu len(resp) verinin kaç byte olduğunu bize iletir.
 print('Downloaded', downloaded / (1024 * 1024), 'MB') # İndirilen verinin miktarının MB cinsinden ekrana yazdırılması. Byte to MB dönüşümü kullanıldı tabii ki.
 print((downloaded / (1024 * 1024)) / (time.time() - start) * 8, 'Mbps') #konunun başında belirttiğim işlemi gerçekleştirdik. Yine aynı şekilde Byte to MB dönüşümü kullandık ve MB/Sn cinsinden hızı bulduk ve 8 ile çarparak mbps cinsine çevirdik.

end = time.time() #indirme işleminin bitiş zamanı saniye cinsinden (Bu olayı araştırmanızı tavsiye ederim keyifli bir olay)
# İndirilen verinin miktarının MB cinsinden ekrana yazdırılması
print('Downloaded', downloaded / (1024 * 1024), 'MB')
# İndirme hızının Mbps cinsinden ekrana yazdırılması
print((downloaded / (1024 * 1024)) / (end - start) * 8, 'Mbps')

#en son tekrar yazdırdık ve bitti.

Kodun tam hali bu şekilde.

Python:
import socket
import time

address = ('speedtest2.vodafone.com.tr', 8080)

GET_REQUEST = b"GET /download HTTP/1.1\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0\r\nConnection: keep-alive\r\n\r\n"

def main():
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 sock.connect(address)
 print('Connected to', address)

 start = time.time()
 sock.send(GET_REQUEST)
 downloaded = 0
 while True:
 resp = sock.recv(1 << 20)
 if not resp:
 break
 downloaded += len(resp)
 print('Downloaded', downloaded / (1024 * 1024), 'MB')
 print((downloaded / (1024 * 1024)) / (time.time() - start) * 8, 'Mbps')

 end = time.time()

 print('Downloaded', downloaded / (1024 * 1024), 'MB')
 print((downloaded / (1024 * 1024)) / (end - start) * 8, 'Mbps')

if __name__ == '__main__':
 main()

Umarım en az şekilde hata yapmışımdır (Hatasız kul olmaz.) Ve umarım eğlenceli ve öğretici bir yazı olmuştur. "Programming Influencer"ların kökünün kuruması dileğiyle. Okuduğunuz için teşekkür ederim.
Unutmayın ki bu program güvenlik açıkları ve optimizasyon sıkıntıları barındırabilir ve profesyonel işlerce kullanılmasını tavsiye etmiyorum.
Bazı konuların bilerek yüzeysel geçildiğini ve araştırmaya teşvik için bunun yapıldığını unutmayın. Araştırın ve öğrenmeye çalışın her şey böyle başlar.
Hocam yanlış anlamazsanız neden speedtest yerine bunu uyguluyoruz ? Belki ben bilmiyorumdur.
 
Hocam yanlış anlamazsanız neden speedtest yerine bunu uyguluyoruz ? Belki ben bilmiyorumdur.
Speedtest yerine bunu uygulamanıza gerek yok. Sadece speedtest'in mantığını kavramaya yardımcı olur ve bazı protokolleri anlamaya yardımcı olur. Herhangi bir tüketicinin bunu yapmasına gerek yok. Hatta daha da kötü olur belki de.
 

Yeni konular

Geri
Yukarı