-1

Я пытаюсь закодировать связь клиент-сервер. Пока мне удается подключиться в первом потоке. Второй поток читает сокет, а третий проверяет, нет ли неожиданного disconection от клиента.System.ObjectDisposedException в сокете и когда закрывать потоки

Моя проблема в том, что я получил исключение System.ObjectDisposedException, когда я пытаюсь прочитать сокет. Если я продолжу работу программы (игнорируя исключение), то такое же исключение произойдет, когда я проверю, все еще подключен сокет.

Сервер представляет собой класс со следующими полями:

static class Server 
    { 
     static ArrayList readList = new ArrayList(); 
     static ArrayList acceptList = new ArrayList(); 

     static public Thread thread1 = new Thread(new ThreadStart(SocketConnector)); 

     static Thread thread2 = new Thread(new ThreadStart(SocketListener)); 
     static Thread thread3 = new Thread(new ThreadStart(SocketClose)); 
     static Thread thread4 = new Thread(new ParameterizedThreadStart(SocketWriter)); 

ReadList используется в считывающем сокете нити (последний образец кода в этом сообщении) acceptList содержит результаты Socket.Accept(). Вот как acceptList заполнен.

static void SocketConnector() 
    { 
    while (true) 
    { 
     sock.Listen(25); 
     actif = sock.Accept(); 

     if (actif != null) 
     { 
      lock (acceptList) 
      { 
       acceptList.Add(actif); 
       Console.WriteLine("IT WORKS"); 
       // that writeline appeared when i try to connect with the client. 
      } 
       actif = null; 
     } 
    } 

Теперь вот как я проверить, если не было никакого неожиданного отключения от клиента:

  static void SocketClose() 
      { 
      while (true) 
      { 
       for (int i = 0; i < acceptList.Count; ++i) 
       { 
        if (((Socket)acceptList[i]).Poll(25, SelectMode.SelectRead) && ((Socket)acceptList[i]).Available == 0) 
        { 


          lock (acceptList) 
          { 
           ((Socket)acceptList[i]).Close(); 
           Console.WriteLine("Client " + ((Socket)acceptList[i]).GetHashCode() + " déconnecté"); 
           acceptList.Remove((Socket)acceptList[i]); 
           i--; 
          } 
         } 
        } 
        Thread.Sleep(5); 
      } 

И последняя часть кода я должен показать, если, как я прочитал мое гнездо.

static void SocketListener() 
    { 
      while (true) 
      { 
       readList.Clear(); 
       lock (acceptList) 
       { 
        for (int i = 0; i < acceptList.Count; i++) 
        { 
         readList.Add((Socket)acceptList[i]); 
        } 
       } 
       if (readList.Count > 0) 
       { 
        Socket.Select(readList, null, null, 1000); 

        for (int i = 0; i < readList.Count; i++) 
        { 
         if (((Socket)readList[i]).Available > 0) 
         { 
          while (((Socket)readList[i]).Available > 0) 
          { 
           Console.WriteLine("Debut Deserialisation"); 

           // get the underlying socket for the TcpClient 
           TcpClient client = new TcpClient(); 
           client.Client = (Socket)readList[i]; 
           NetworkStream ns = client.GetStream(); 
           BinaryReader reader = new BinaryReader(ns); 
           Message received = new Message(); 

           Console.WriteLine(received.msg); 
           Console.WriteLine(received.user); 
           Console.WriteLine(received.targetChatroom); 


           // Deserialisation 
           int length = reader.ReadInt32(); 
           byte[] msgArray = reader.ReadBytes(length); 
           received.msg = Encoding.UTF8.GetString(msgArray); 

           length = reader.ReadInt32(); 
           msgArray = reader.ReadBytes(length); 
           received.user = Encoding.UTF8.GetString(msgArray); 

           length = reader.ReadInt32(); 
           msgArray = reader.ReadBytes(length); 
           received.targetChatroom = Encoding.UTF8.GetString(msgArray); 

           ns.Close(); 
          } 
         } 
        } 
       } 
      } 

я понял, что, возможно, мой сокет был закрыт по линии ns.Close(), и это вызывает ошибку. С ns.Close() я просто попытался закрыть созданный мной поток, чтобы получить данные из сокета, а не закрыть сам сокет. Я попытался удалить эту строку ns.Close(), и ObjectDisposedException больше не появляется! Однако теперь я получил исключение OutOfMemoryException на линии:

в потоке для чтения. Я считаю, что это исключение вызвано тем, что поток не закрыт.

EDIT: Исключение OutOfMemoryException происходит из кода клиента. Проблема решена здесь.

Обнаружение разъединения работает и десериализация.

Мой вопрос: когда следует закрыть этот поток ???

+0

Много кода, но все еще не завершено. Неясно, на каком потоке (ей) это выполняется, и 'new Thread (новый ThreadStart (SocketClose));' не похож на отличный инструмент.Ваша резьба для чтения должна взаимодействовать при остановке и закрытии. –

+0

@ Хенк Холтерман Вы правы. Я редактировал, чтобы показать, какой образец кода принадлежит тому потоку. Нить «SocketClose» - это поток, который проверяет, все еще подключен сокет, если другой хост не отправляет вам пакет, когда он отключается (например, потому что он отключен несправедливо). Возможно, имя не очень хорошо выбрано. – Csi

ответ

0

При использовании Socket.Select, нет необходимости в дополнительной нити - просто включите сокеты в параметр checkError, а также в параметр checkRead.

Может показаться, что бит разъединения работает, потому что во время теста он закрыл ваш сокет, но я предполагаю, что удаленное соединение действительно отправило действительное сообщение об отключении (в отличие от «неожиданного» разъединения), в результате чего ваше чтение чтобы задушить на закрытом гнезде.

Вы должны ожидать какие-либо операции на Socket бросить SocketException для неожиданных ошибок, и ожидает сообщение ровно 0 байт для регулярного отключения.

Я не использую BinaryReader так много, но я ожидаю, что он бросит EndOfStreamException на int length = reader.ReadInt32();.

Смежные вопросы