TIME_WAIT içinde bir soket nasıl zorla kapatılır?

Linux üzerinde bazen çöken belirli bir program çalıştırıyorum. Bundan sonra hızlı bir şekilde açarsanız, ilk seferde olduğu gibi 49200 yerine 49201 soketini dinliyor. netstat, 49200'ün TIME_WAIT durumunda olduğunu ortaya koyuyor.

Bu soketi TIME_WAIT durumundan hemen çıkmaya zorlamak için çalıştırabileceğiniz bir program var mı?

Çözüm
/etc/init.d/networking restart

Biraz daha açıklayayım. İletim Kontrol Protokolü (TCP) iki uç nokta (program) arasında çift yönlü, düzenli ve güvenilir bir veri iletim protokolü olarak tasarlanmıştır. Bu bağlamda, güvenilir terimi, paketlerin arada kaybolması durumunda yeniden iletileceği anlamına gelir. TCP, eşten alınan tek bir veya bir dizi paket için geri Onay (ACK) paketleri göndererek güvenilirliği garanti eder.

Bu durum sonlandırma isteği/cevabı gibi kontrol sinyalleri için de geçerlidir. RFC 793 TIME-WAIT durumunu aşağıdaki gibi tanımlar:

TIME-WAIT - beklemeyi temsil eder emin olmak için yeterli zaman geçmesi uzak TCP bağlantısının onayını aldı fesih talebi.

Aşağıdaki TCP durum diyagramına bakın:

TCP çift yönlü bir iletişim protokolüdür, bu nedenle bağlantı kurulduğunda istemci ve sunucu arasında bir fark yoktur. Ayrıca, herhangi biri çıkma çağrısı yapabilir ve kurulan bir TCP bağlantısını tamamen kapatmak için her iki eşin de kapatma konusunda anlaşması gerekir.

İlk pes edene aktif yakınlaştırıcı, diğer eşe de pasif yakınlaştırıcı diyelim. Aktif yakınlaştırıcı FIN gönderdiğinde, durum FIN-WAIT-1'e gider. Daha sonra gönderilen FIN için bir ACK alır ve durum FIN-WAIT-2'ye gider. Pasif yakınlaştırıcıdan da FIN aldığında, aktif yakınlaştırıcı FIN'e ACK gönderir ve durum TIME-WAIT'e gider. Pasif yakınlaştırıcının ikinci FIN için ACK almaması durumunda, FIN paketini yeniden iletecektir.

RFC 793 TIME-OUT değerini Maksimum Segment Ömrünün iki katı veya 2MSL olarak ayarlar. Bir paketin İnternet'te dolaşabileceği maksimum süre olan MSL 2 dakika olarak ayarlandığından, 2MSL 4 dakikadır. Bir ACK'ya ACK olmadığından, pasif göndericinin FIN'ine ACK almamış olması ihtimaline karşı (teorik olarak), TCP/IP protokolüne doğru bir şekilde bağlı kalırsa, aktif yakınlaştırıcı 4 dakika beklemekten başka bir şey yapamaz.

Gerçekte, kayıp paketler muhtemelen nadirdir ve hepsi LAN içinde veya tek bir makinede gerçekleşiyorsa çok nadirdir.

Soruyu kelimesi kelimesine cevaplamak için, TIME_WAIT'te bir soket nasıl zorla kapatılır?, Hala orijinal cevabıma sadık kalacağım:

/etc/init.d/networking restart

Pratik olarak konuşmak gerekirse, WMR'nin bahsettiği gibi SO_REUSEADDR seçeneğini kullanarak TIME-WAIT durumunu yok sayacak şekilde programlarım. SO_REUSEADDR tam olarak ne yapar?

Bu soket seçeneği çekirdeğe şunları söyler bu bağlantı noktası meşgul olsa bile (in TIME_WAIT durumu), devam edin ve yine de tekrar kullanın. Eğer meşgulse, ama başka bir eyalet ile, yine de alacaksınız zaten kullanımda olan bir adres hatası. Bu sunucunuz kapatılmışsa kullanışlıdır aşağı ve sonra hemen yeniden başlatıldı üzerinde soketler hala aktifken liman. Şunu bilmelisiniz ki eğer beklenmedik herhangi bir veri gelirse sunucunuzun kafasını karıştırır, ancak bu mümkündür, ancak olası değildir.

Yorumlar (5)

Çalıştırdığınız programın kaynak koduna sahip olup olmadığınızı bilmiyorum, ancak eğer öyleyse, soket TIME_WAIT durumunda olsa bile aynı yerel adrese bağlanmanıza izin veren setsockopt(2) aracılığıyla SO_REUSEADDR'yi ayarlayabilirsiniz (bu soket aktif olarak dinlemiyorsa, bkz. socket(7)).

TIME_WAIT durumu hakkında daha fazla bilgi için Unix socket FAQ adresine bakın.

Yorumlar (5)

Bildiğim kadarıyla programınıza daha iyi bir sinyal işleyici yazmak dışında soketi zorla kapatmanın bir yolu yok, ancak zaman aşımının ne kadar süreceğini kontrol eden bir /proc dosyası var. Bu dosya

/proc/sys/net/ipv4/tcp_tw_recycle

ve bunu yaparak zaman aşımını 1 saniyeye ayarlayabilirsiniz:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 

Ancak, bu sayfa bu değişkeni ayarlarken olası güvenilirlik sorunları hakkında bir uyarı içerir.

Ayrıca ilgili bir dosya da var

/proc/sys/net/ipv4/tcp_tw_reuse

TIME_WAIT soketlerinin yeniden kullanılıp kullanılamayacağını kontrol eder (muhtemelen herhangi bir zaman aşımı olmadan).

Bu arada, çekirdek belgeleri bu değerlerden herhangi birini 'teknik uzman tavsiyesi/isteği' olmadan değiştirmemeniz konusunda sizi uyarıyor. Ki ben uzman değilim.

Program 49200 numaralı bağlantı noktasına bağlanmayı deneyecek ve ardından bağlantı noktası zaten kullanımdaysa 1 artıracak şekilde yazılmış olmalıdır. Bu nedenle, kaynak kodun kontrolü sizdeyse, bu davranışı birkaç saniye beklemek ve artırmak yerine aynı bağlantı noktasında tekrar denemek şeklinde değiştirebilirsiniz.

Yorumlar (3)