TCP Ne Kadar Güvenilir – 3

Bir önceki yazımızda (TCP Ne Kadar Güvenilir – 2) recv() metoduna kafayı takmıştık.

recv() metodu çağrılması esnasında karşı uçtaki cihazın bir sebeple tamamen erişilemez olması durumunda (örneğin elektrik kesilmesi, ağ kablosunun çekilmesi/kopması, cihazın reset alması vb.) recv()’in dönmediğini ifade etmiştik. Bu durumu bir örnekle göstermiştik. Aslında eğer sanallaştırma yapabilme imkanınız varsa (örneğin VirtualBox), kablo bağlantısını koparma gibi özellikleri VirtualBox sunmaktadır. recv()’in kablo bağlantısı koparılsa bile sonlanmadığını bu şekilde de test edebilirsiniz.

Bu yazıda, aynı durumda yani kablo çekilmesi veya reset alınması durumunda, send() durumunu irdeleyeceğiz. Bu seferki durum biraz daha karmaşık.

send() metoduyla olan denemelerimizde “Cable Connected” ile oynayacağız (ifade edildiği gibi recv() için de aynısını uygulayabilirdik). Şimdi konumuza dönelim.

iki taraf var (istemci-sunucu), bunlardan birisi send() fonksiyonunu çağırırken karşı taraf bağlantıyı kapatırsa (power down değil, soket kuralına uygun şekilde kapatılıyor) nasıl bir durum olur?

Cevap tahmin edilebileceği gibidir, yani send() bekleme yapmadan dönecektir. Bu durum recv()’in davranışı ile aynıdır.

Durumu karmaşıklaştıralım. taraflardan birisi send() çağırmışken diğeri reset alırsa yada kablosu çekilirse (resimdeki check box) ne olur peki? Evet TCP stack rahmetlik olur, yani karşıya kimse durumu haber vermez, peki daha daha ne olur? Denemesi bedava. Sanal makinenize bir adet linux dağıtımı kurunuz ve send() eden tarafın değil, recv() eden tarafın kablosunu çekiniz. Ne bekliyorsunuz? recv() aynı durumda dönmemişti. send() de mi dönmeyecek sizce? Test ettikten sonra göreceksiniz ki, send dönecektir. Peki bu nasıl oldu? recv() aynı durumda beklemişti yani dönmemişti.

send() metodu gönderilecek veriyi kendi TCP stack’ine iletir ve bu verinin artık iletileceğini düşünür. Tabiki bu veriyi TCP stack karşı tarafa iletecektir. Ancak send() eden tarafın TCP stack’i gönderdiği tarafın down olduğundan habersizdir (karşı tarafın TCP stack’i ulaşılamaz olduğu için). Uygulamamız send()’den başarılı bir şekilde dönecektir ancak tabiki TCP stack bu veriyi iletemeyecektir. Evet uygulamamız bu durumu farkedemeyecektir.

Felaket senaryosu henüz bitmedi. Uygulamanız hatadan habersizdir elbette. Uygulamamız send()’i çağırmaya devam ediyor olsun (mesela yoklama atılıyor). send() gönderilen veri miktarına ve işletim sisteminin türü ve TCP stack büyüklüğüne göre değişken olmakla birlikte belirli bir çağırma miktarı boyunca send() bloklama yapmadan (anında) dönecektir. Ancak TCP stack dolunca send() bloklayacaktır. Yani send dönmeyecektir.

Normal şartlar altında send() bloklamaz diyoruz yani. Şöyle örnekleyelim. Varsayalım ki TCP stack 100 MB olsun. Siz ise her send()’de 1 MB veri gönderiyorsunuz. send() 100 kez çağırılsa bile yukarıdaki durumlarda (reset, kablo çekilmesi) bloklamaz. Ancak 101’inci send() bloklayacaktır, yani sonlanmayacaktır.

Peki normalde bu durum nasıl işlerdi? 100 MB TCP stack’e 1 MB veri yazıldığında 99 MB daha yazılacak yer bulunurdu TCP stack’te. Ancak TCP stack bu veriyi gönderdikten sonra bu miktar tekrar 100 MB’a çıkarılırdı.

Ancak kablo çekilince veya reset durumunda, gönderen tarafın TCP stack’i arka planda bu veriyi tekrar tekrar göndermeye çalışmaya devam edecektir. Bu esnada tabiki send()’de çağırılmaya devam edeceğinden TCP stack boyutu azalacak ve nihayetinde yer kalmayınca send() bloklayacaktır. Evet sunucu yazılımı bu send() metodunu bu şekilde çağırıyorsa o sunucuya geçmiş olsun dileklerinizi iletebilirsiniz. Böyle bir tasarımda ister thread, ister process olarak bu bağlantı işlesin, bir servis dışı bırakma atağına açık bir durum oluşmuştur denilebilir.

man send

komutunu linux terminale yazınca aşağıdaki ifade dikkatinizi çekecektir:

“When  the  message  does not fit into the send buffer of the socket, send() normally blocks, unless the socket has been placed in nonblocking I/O mode.”

Burada buffer ile ifade edilen kavram bizim stack dediğimiz kavramdır.

Peki bunun çözümü nedir diye soracaksınız. İlerleyen yazılarımızda hem recv() hem de send() için tasarım ve çözümler önereceğiz. Bloklama kavramını detaylandıracağız.

Sağlıcakla kalınız,

Leave a Reply

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