2016-03-18 15 views
4

kapanışı ile ilgili sorunlar şu anda basit bir istemci sunucu sohbet programı üzerinde çalışıyorum (C# 'da istemci sunucusu iletişimine girmek istedim). Sunucudan düzgün şekilde ayrılmak dışında çok çalışır.TcpClient ve NetworkStream'in

client.Client.Disconnect(false); // client is the TcpClient 
client.Close(); 

sunucusunda istemciden mesajlar için bekleyen bir dişli döngü vardır:

private void StartChat() 
{ 
    int requestCount = 0; 
    byte[] bytesFrom = new byte[10025]; 
    string dataFromClient = null; 
    string rCount = null; 

    while (true) 
    { 
     try 
     { 
      requestCount++; 

      NetworkStream stream = tcpClient.GetStream(); 

      int bufferSize = (int)tcpClient.ReceiveBufferSize; 
      if (bufferSize > bytesFrom.Length) 
      { 
       bufferSize = bytesFrom.Length; 
      } 

      stream.Read(bytesFrom, 0, bufferSize); 
      dataFromClient = System.Text.Encoding.UTF8.GetString(bytesFrom); 
      dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$")); 
      rCount = Convert.ToString(requestCount); 

      string message = client.Name + " says: " + dataFromClient; 
      program.Broadcast(message); 

     } 
     catch(Exception ex) when (ex is ObjectDisposedException || ex is InvalidOperationException || ex is System.IO.IOException) 
     { 
      program.UserDisconnected(client); 
      break; 
     } 
     catch(ArgumentOutOfRangeException ex) 
     { 
      Debug.WriteLine(ex.ToString()); 
      break; 
     } 
     catch(Exception ex) 
     { 
      Debug.WriteLine(ex.ToString()); 
      break; 
     } 
    } 

istemci bağlantısını kesmeden ben bağlantıyı kapatmak için buraya Bu kodu kullanmak Ýstemcide

Yukarıda gösterilen kod ile işlev her zaman akışı almayı ve böyle bir çıktı üretmeyi sağlar:

\0\0\0\0\0\0\0 [and so on]Bu durumda $ dizin olmadığı için ArgumentOutOfRangeException atılacak. Bu durumda $. Döngüden kaçınmak ve bitmek için break ekledim. Şaşırtıcı bir şekilde, ObjectDisposedException atılmayacaktır. Ayrıca System.IO.IOException atılmayacaktır, ancak akım kapatıldığı için bağlantı reddedilmiş olmalıdır.

Sunucuya bağlı istemci uygulamasını kapatırsam, sunucu döngüyü durdurmaz, yalnızca istemcinin bağlantısı kesildiği için gelmeyecek bir akış bekler.

İstemcinin bağlantısı kesilip kesilmediğini nasıl algılayabilirim? İstemci bağlantısını bir bağlantıyı kapatmak için uygun bir şekilde kapattığım yoldur?

Yardımlarınız için teşekkürler!

Güncelleme:

private void StartChat() 
{ 
    int requestCount = 0; 
    byte[] bytesFrom = new byte[10025]; 
    string dataFromClient = null; 
    string rCount = null; 

    while (true) 
    { 
     try 
     { 
      requestCount++; 

      NetworkStream stream = tcpClient.GetStream(); 
      stream.ReadTimeout = 4000; 

      int bufferSize = (int)tcpClient.ReceiveBufferSize; 
      if (bufferSize > bytesFrom.Length) 
      { 
       bufferSize = bytesFrom.Length; 
      } 


      // Wait for a client message. If no message is recieved within the ReadTimeout a IOException will be thrown 
      try 
      { 
       int bytesRead = stream.Read(bytesFrom, 0, bufferSize); 
       stream.Flush(); 

       if (bytesRead == 0) 
       { 
        throw new System.IO.IOException("Connection seems to be refused or closed."); 
       } 
      } 
      catch (System.IO.IOException) 
      { 
       byte[] ping = System.Text.Encoding.UTF8.GetBytes("%"); 
       stream.WriteTimeout = 1; 

       stream.Write(ping, 0, ping.Length); 
       continue; 
      } 


      dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom); 
      dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$")); 
      rCount = Convert.ToString(requestCount); 

      string message = client.Name + " says: " + dataFromClient; 
      program.Broadcast(message); 

     } 
     catch(Exception ex) when (ex is ObjectDisposedException || ex is InvalidOperationException || ex is System.IO.IOException) 
     { 
      Debug.WriteLine(ex.ToString()); 
      program.UserDisconnected(client); 
      break; 
     } 
     catch(ArgumentOutOfRangeException ex) 
     { 
      Debug.WriteLine(ex.ToString()); 
     } 
     catch(Exception ex) 
     { 
      Debug.WriteLine(ex.ToString()); 
      break; 
     } 
    } 
} 

cevap

3

Sen stream.Read dönüş değerini kontrol etmelidir - bu bayt aslında okuma sayısını döndürür.

İstemci bağlantısı kesildiğinde, 0 okunacaktır ve okunan verileri okuduğunda, okunan bayt sayısı genellikle arabellek boyutundan daha azdır. İstemci doğru bağlantıyı kapatır

  • ve saptanabilir oldu 0 bayt
  • şey alırsınız: Bir istemci bağlantısını sonlandırır yaparken en son yorumuna cevaben

    int bytes = stream.Read(bytesFrom, 0, bufferSize); 
    if (bytes == 0) 
    { 
        // client has disconnected 
        break; 
    } 
    
    dataFromClient = System.Text.Encoding.UTF8.GetString(bytesFrom, 0, bytes); 
    

    , üç şey olabilir müşteri "gone" ama hiç sinyal senin sonunu gönderilen bir istisna

  • neden

Bu son durumda sunucu, etkin bir bağlantı varmış gibi davranmaya devam eder, veri gönderilmeye başlayana kadar açık bir şekilde başarısız olur. Bu yüzden birçok protokol bir bağlantı zaman aşımı ve/veya canlı bir mekanizma ile çalışır.

+0

Bu, istemcinin kaybolup gitmediğini algılayamayacağınız anlamına mı geliyor? Docu'ya bakmak bir ObjectDispoedException veya en azından bir IOException atması gerektiğinden daha fazla okunamayacağı için – chris579

+0

A _graceful_ disconnect istisnai bir durum değildir ve 'stream.Read()' döndürme 0 ile algılanır. Bir istisna eylemcisi var, ama kendiniz atmayın ve sonra kullanmaya çalıştığınız sürece ObjectDisposedException 'atılmış olduğundan şüpheleniyorum. –

+0

Haklısınız, bu nesne hala orada olmadığı ve çöp toplayıcı tarafından silinmediği veya elden çıkarılmadığı sürece DisposedException atılmayacak. Ancak, büyük teşekkürler, bu işe yaradı! Cevabınızı en kısa zamanda kabul edeceğim. Düzenleme: İstemciyi kapatırsam, döngü sona ermez ve sunucu uygulaması kapanana kadar kalır. Bunu nasıl düzeltebilirim? – chris579

1

int bytesRead = stream.Read (...); if (bytesRead == 0) // İstemci devre dışı bırakıldı

+0

Peki ya yavaşsın. Yukarıdaki cevaba bakın;) – chris579

+0

ya ... Buralarda yeteri kadar geliştirici var biliyorum, belki de site yeni bir yorum/cevap olduğunda bir insanı bilgilendirebilir ... : p – ABuckau

+0

Evet :) Henüz bir cevap beklemede sadece ilk cevabımda yorumuma bakıyorum. Belki bu konuda bana yardımcı olabilirsiniz;) – chris579

İlgili konular