2012-08-06 40 views
9

Belirsiz bir süre için veriyi ileri geri itmeyi amaçlayan bir istemci/sunucu ilişkisi üzerinde çalışıyorum.C soketindeki bağlantı kesilmesi nasıl tespit edilir C#

Üstesinden gelmeye çalıştığım sorun, istemci tarafındadır, çünkü bağlantıyı kesmenin bir yolunu bulmayı başaramam.

Sadece IO İstisnalarını yakalamadan, üç Seçme Noktasının her birinde soket yoklamaya kadar, diğer insanların çözümlerinde birkaç geçiş yaptım. Ayrıca, bir anketin bir kombinasyonunu kullanarak, soketin 'Uygun' alanına bir kontrol ile çalıştım. Sunucu tarafında

// Something like this 
Boolean IsConnected() 
{ 
    try 
    { 
     bool part1 = this.Connection.Client.Poll(1000, SelectMode.SelectRead); 
     bool part2 = (this.Connection.Client.Available == 0); 

     if (part1 & part2) 
     { 
      // Never Occurs 
      //connection is closed 
      return false; 
     } 
     return true; 
    } 
    catch(IOException e) 
    { 
     // Never Occurs Either 
    } 
} 

, bir 'boş' karakteri yazmak için bir girişim (\ 0) müşteriye bir IO İstisna zorlar ve sunucu istemci (oldukça kolay konser) bağlantıyı kestiğini tespit edebilir.

İstemci tarafında aynı işlem bir istisna getirmez.

// Something like this 
Boolean IsConnected() 
{ 
    try 
    { 

     this.WriteHandle.WriteLine("\0"); 
     this.WriteHandle.Flush(); 
     return true; 
    } 
    catch(IOException e) 
    { 
     // Never occurs 
     this.OnClosed("Yo socket sux"); 
     return false; 
    } 
} 
Ben anket yoluyla bağlantı kesme saptanmasında yaşıyorum inanıyoruz bir sorun, benim sunucu henüz beri müşteriye geri hiçbir şey yazmadı, ben oldukça kolay bir SelectRead üzerinde sahte karşılaşmak olmasıdır

son kontrol ... Burada ne yapacağından emin değilim, bulabildiğim bu saptamayı yapmak için her seçeneği takip ettim ve hiçbir şey benim için% 100 olmadı ve sonuçta benim amacım bir sunucuyu (veya bağlantıyı) tespit etmektir) başarısızlık, müşteriyi bilgilendirmek, yeniden bağlanmak için beklemek, vb. Bu yüzden bunun bir ayrılmaz parça olduğunu hayal edebileceğinizden eminim.

Herkesin önerilerini takdir edin. Zamanın önündedir.

DÜZENLEME: Bu soruyu görüntüleyen herkes, aşağıdaki cevabı ve bunun için FİNAL Yorumlarım'a dikkat etmelidir. Bu sorunun üstesinden nasıl geldiğimi açıklığa kavuşturdum, ancak henüz 'Q & A' stili bir gönderi yaptık.

+0

Sadece IOExceptions'ı yakalayın ve bir zaman aşımı kullanın. Diğer tüm bu anahtarlığa ihtiyacın yok. – EJP

+0

Bunu zaten denedim (yazımı gerçekten okumadınız ...) ve isabetli ya da özledim. Bir saniyeden sonra zaman aşımına uğrayan bir okuma işlemi bir bağlantı kesme işlemini zorlayan bir IO'ya neden olur ... Ama ya veri almamış olsaydım ...? – DigitalJedi805

+0

Yazınızı okudum. 'Vur ve kaçır' değil, hem lokal hem de uzaktan tamponlama yapan asenkron veriye tabidir. Başarısız bir bağlantının ilk yazısında, henüz algılanmadığından, bir istisna alamazsınız: TCP, yeniden deneme girişimlerini zamanladıktan sonra, sonraki bir yazıda alırsınız. – EJP

cevap

12

Bir seçenek TCP'yi canlı paketler kullanmaktır. Onları Socket.IOControl() numaralı çağrıyla açarsınız. .

Socket socket; //Make a good socket before calling the rest of the code. 
int size = sizeof(UInt32); 
UInt32 on = 1; 
UInt32 keepAliveInterval = 10000; //Send a packet once every 10 seconds. 
UInt32 retryInterval = 1000; //If no response, resend every second. 
byte[] inArray = new byte[size * 3]; 
Array.Copy(BitConverter.GetBytes(on), 0, inArray, 0, size); 
Array.Copy(BitConverter.GetBytes(keepAliveInterval), 0, inArray, size, size); 
Array.Copy(BitConverter.GetBytes(retryInterval), 0, inArray, size * 2, size); 
socket.IOControl(IOControlCode.KeepAliveValues, inArray, null); 

Tut: Sadece can sıkıcı biraz onu girdi olarak bir bayt dizisi alır, yani geçmek bayt dizisi için verilerinizi dönüştürmek zorunda İşte 10000ms kullanarak bir örnek, bir 1000ms yeniden deneme ile canlı tutmak var Canlı paketler sadece başka veri göndermediğinizde gönderilir, böylece her veri gönderdiğinizde 10000 ms zamanlayıcı sıfırlanır.

+0

Harika, teşekkürler Joel, Dev sistemime girer girmez en kısa zamanda bir dönüş yapacağım. – DigitalJedi805

+0

Hey Joel, sanırım buradaki fikri anladım ama eğer yanılıyorsam lütfen beni düzeltin; IOControl yöntemi, bir 'KeepAlive' paketinin bir prize zamanında teslim edilmesini sağlar. Yukarıdaki kodu hem benim SocketServer.Client hem de SocketClient yapıcılarına ekledim (neredeyse sözcük için). Zamanlayıcıyı bir saniyeliğine düşürdüm (çünkü bu her iki tarafta da 'okuma' zaman aşımı oluyordu) ama benim StreamReader.ReadLine (Sadece bunu stratejimin benim olmamayacağına karar verdiğimi farkettim) hiçbir veriyi yakalamıyor ... I Tam olarak neden diziye koyduğumuzu koyduğumuzdan emin olmadığımı söylemeliyim; onu sonlandırabilir miyim? – DigitalJedi805

+0

Aslında sadece bir StreamReader.Read çağrısı ile aynı şeyi çalıştırmayı denediniz ve yine de hiçbir yönde hiçbir şey elde edemediniz. Bu kavramı tam olarak anlamadığım olabilir. – DigitalJedi805