2010-04-19 23 views
7

TCP bağlantılarını kabul eden bir sunucuda garip bir sorun var. Normalde bazı süreçler beklemesine rağmen, bazı bağlantılarda bu bağlantıyı askıya alır.Perl TCP sunucu betiğimde neden birçok TCP bağlantısı var?

Uzun versiyon:

sunucu Perl ile yazılmış ve yeniden bayrağıyla bir $srv soket bağlayan ve Sonrasında == 5. dinlemek edilir

, bu $clt=$srv->accept(); do_processing($clt); $clt->shutdown(2);

istemci bir döngü ile 10 süreçlerine çatallar C de yazılmış çok basittir - bazı satırlar gönderir, sonra tüm satırları alır ve shutdown(sockfd, 2); yapar Hiçbir şey eşzamansız devam eder ve sonunda her iki gönderi ve alma kuyrukları boştur (netstat tarafından bildirildiği gibi).

Bağlantılar sadece ~ 20ms. Tüm müşteriler aynı şekilde davranırlar, aynı uygulama vb. Davranırlar. Şimdi istemci 1'den X bağlantıyı kabul ettiğimi ve 2. istemciden bir başka X kabul ettiğimi söyleyelim. İşlemler hala her zaman boşta olduklarını bildiriyorlar. İstemci 3'ten başka bir X bağlantısı eklerseniz, aniden sunucu işlemleri kabul edildikten hemen sonra başlatılmaya başlar. accept();'dan sonra yaptıkları ilk engelleme işlemi while (<$clt>) ...'dur - ancak herhangi bir veri almazlar (ilk denemede). Aniden tüm 10 süreç bu durumda ve beklemeyi bırakmıyor. strace üzerinde, sunucu işlemleri read()'da asılı kalıyor, bu da mantıklı. Bu sunucuya ait olan TIME_WAIT numaralı bağlantıda bir çok bağlantı vardır (sorun ortaya çıkmaya başladığında ~ 100), ancak bu kırmızı bir ringa balığı olabilir.

Burada neler olabilir?


Bazı analizlerden sonra: Bir sonraki denemeye başlamadan önce istemcinin hatalı olduğunu ve önceki bağlantıları düzgün şekilde kapatmayacağını belirtti. Yük dengeleme listesinin başında bulunan sunucular eski bağlantıları kalmıştı.

+1

Tüm soketlerinizde arabelleğe almayı devre dışı bıraktınız mı? Daha fazla örnek kod göndermeniz gerekebilir. –

+0

Burada kod olarak neler sağlayabileceğimi bilmiyorum - gerçekten basit. Sunucu satırlarda çalışır, bu yüzden oklar satır tamponludur ve '<...>' ile işlenir - burada başka bir şey ifade etmedikçe? İstemci C kodu bir standart 'connect (...);' ve 'yazmak (sockfd, request, ...);' - Burada arabelleğe almayı devre dışı bırakmaya ve geri raporlamaya çalışacağım. – viraptor

+0

@Eric Strom: Şaşkınım şimdi - tamponlamayı devre dışı bırakarak ne demek istediniz? İstemci tarafında basit bir 'write (...)' kullanıyorum - tabii ki bir nagle var, ama bu sonraki 0.2s (daha fazla ya da daha az) transferini garanti ediyor. Peki aklında ne tür bir tamponlama var? – viraptor

cevap

0

Uzun süre (yaklaşık iki dakika kadar) dalgalanıyor mu ve sonra tekrar yayılıyor mu? Bu durumda sisteminizde maksimum açık dosya sınırı olmayabilir.

+0

Açık dosyalar ulimit 1024'tür. Sunucu hiçbir zaman ~ 100 ölü (time_wait) bağlantı üzerinden geçmez ve hiçbir zaman 10'un üzerinde (çatallı işlem başına 1 adet) canlı bağlantı yoktur. Engellenen bağlantılar başladığında, bağlantıların yaklaşık on üzerinde olurlar (3 zaman aşımına uğrar, zaman aşımı koruması devreye girip işlemi yeniden başlatana kadar, biri ~ 5 saniye boyunca bloke edilir). – viraptor

1

Muhtemelen sorununuz için bir çözüm değil, ancak gelecekte karşılaşacağınız bir sorunu çözebilir: İşiniz bittiğinde soketleri kapatmayı unutmayın()! shutdown() akışı kesecek, ancak yine de bir dosya tanıtıcısı yer.

Strace'nin read() işlevinde kalmış işlemleri gösterdiğinden beri, sorun, istemcinin gönderilmesini beklediğiniz verileri göndermemesi gibi görünüyor. İstemcinizi düzeltmeniz veya sunucu işlemlerine ölü istemcilerde hayatta kalabilmeleri için bir alarm() eklemeniz gerekir.