TCP Ne Kadar Güvenilir – 2

Bu yazımızda TCP’nin sıklıkla karşılaşılmayabilecek, ancak kritik bir problemini açıklayacağız. Bu problemi açıklamadan önce send() ve recv() metotlarının aslında TCP stack’i aracı yaparak işlevlerini gördüklerini ifade etmiştik. Bir soket kapandığı zaman kapatmayı tetikleyen yazılımın bulunduğu bilgisayardaki TCP stack’in karşı taraftak TCP stack’a durumu bildirdiğini ifade etmiştik. Bu cümleyi ne kadar tekrarlasak o kadar önemli, çünkü aslında iletişim kuranlar TCP stack’ler. Programlar TCP stack’leri aracı olarak kullanıyorlar. Paketlerdeki ACK’leri, checksum’ları, akış kontrolünü (bu terimleri bilmiyorsanız boşverin) uygulamalar değil TCP stack kontrol etmektedir.

Problemi tanımlayalım

İstemci-sunucu arasında bir bağlantı kurulmuş durumda olduğunu düşünelim. Bir mesajlaşma programı gibi ara ara sohbet iletileri gelip gidiyor.

Sunucuda istemciyle olan bağlantıyı tutan bir istemci soket vardır, (tabiki bir de sunucu soket, ancak bu konumuzla alakalı değil)
İstemcide sunucuyla iletişimi sağlayan bir istemci soket var.
İstemcinin bilgisayarının bağlandığı mekandaki elektrik gitti. Yedek güç kaynağı vb. de yok. Yani bilgisayar kapandı. Bunun doğal sonucu olarak istemcinin TCP stack’i artık ölüdür denilebilir. Kimse sunucunun TCP stack’ine bu durumu bildiremeyecek yani. TCP stack ise recv() fonksiyonu içerisinde olduğunu düşünelim.

Sizce, recv() bir hata ile veya hiç veri okumadan mı dönecek? Böyle bir durumda ne beklersiniz. İlk olarak recv()’in davranışını test edebilirsiniz. Soket Programlama – 2 yazımızdaki sunucu kodunu aşağıdaki gibi değiştirerek recv()’in davranışını gözlemleyelim:

import socket
import time

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((”, 9000))
s.listen(5)
conn, addr = s.accept()

time.sleep(100000)

conn.close()

Evet yeterince beklediğinizi düşünüyorsanız her iki programı da kapatabilirsiniz. recv()’in dönmediğini gördünüz. sleep süresini 10 saniye olarak değiştirip tekrar programı çalıştırınız ve recv()’in 10 saniye sonra sonlanacağını göreceksiniz. Bunun sebebi conn.close() metodu ile soketin kapatılması ve TCP stack’in bu durumu istemcinin TCP stack’ine iletmesidir. Yani recv()’in sonlamasının sebebi (bir okuma yapmaya çalışmasına rağmen) sunucunun soketi kapatması ve sunucu TCP stack’in durumu istemciye bildirmesidir.

Yukarıdaki ip uçlarını göz önünde bulundurursak, istemci recv() yaparken sunucu (veya tam tersi de geçerli) elektriksel veya başka bir sebeple kapanırsa ne olur? Cevap sizi şaşırtacak cinsten, recv() bunu algılayamayacak, ve ister inanın ister inanmayın oldukça uzun bir süre sonra recv() dönecektir. Eğer recv() fonksiyonu sunucuda çağrıldığı esnada bu durum gerçekleşirse, sunucu ister bu işlemi ayrı bir thread’de isterse ayrı bir process’de yapsın, kaynaklarını israf etmiş olacaktır. Hatta, bu durumun kendisi bir atak olarak kullanılabilir. Şöyle düşünelim, bir linux işletim sisteminde sunucu, her istemci için ayrı bir thread/process açılıyor olsun. Böyle bir atak ile sunucu servis dışı bırakılabilir.

Sağlıcakla kalınız

Leave a Reply

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