2016-09-03 3 views
2

Я начал изучать программирование сокетов в последнее время и написал простой async tcp-сервер, который может отправлять полученные от отдельных клиентов только штрафы. здесь упрощенный код для него:как сетевой поток обнаруживает разъединение

//accpet loop 

while (true) 
{ 
    var client = await listener.AcceptTcpClientAsync(); 
    new AppClient(client).Start(); 
} 

// and here is the start method in AppClient class 
public async void Start() 
{ 
     /// TcpClient is a class property which is in scope of this method 
     using (var stream = TcpClient.GetStream()) 
     { 
      string message = string.Empty; 
      byte[] buffer = new byte[1000]; 
      int bytesRead = 0; 
      while (true) 
      { 
       try 
       { 
        bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); 
       }   
       catch (Exception ex) 
       { 
         MessageBox.Show(ex.Message); 
         break; 
       } 

       // decode simple text message 
       message += Encoding.UTF8.GetString(buffer, 0, bytesRead); 


      } 
     } 
    } 

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

Я делаю что-то неправильно?

+2

Вы действительно не должны делать 'catch (Exception ex)' - это такой анти-шаблон. – Enigmativity

+0

Спасибо, я запомню это. – SHM

+0

Для того, что он делает, нет ничего плохого в catching Exception –

ответ

0

Это не «обнаружение» разъединения, это trhows и исключение, потому что .ReadAsync постоянно пытается получить, если есть данные, доступные для чтения, если есть запись в буфер, если длина данных == длина буфера завершите функцию. Все эти шаги (возможно, есть больше) связаны с Stream, который связан с socket. Затем, если сокет закрыт (по коду или вручную), поток закрывается, если вы попытаетесь сделать что-либо с закрытым потоком, будет выбрано исключение.

+0

Readasync проверяет только один раз, ожидая его, как только данные будут доступны в сокете, остальная часть id метода будет выполнена. – SHM

1

Вы должны использовать .ReadAsync() с отменой толку. Затем измените цикл, чтобы проверить значение маркера. Когда вы хотите убить клиента, вы затем сигнализируете токен.

Также проверьте свою переменную bytesRead. Если он возвращается как 0, соединение просто закрывается.

+0

Большое спасибо за отзыв. однако bytesRead никогда не равен нулю, метод ReadAsync с ожиданием приостанавливает метод до тех пор, пока не будет прочитана какая-либо вещь. – SHM

+0

Он вернет 0, если серверная сторона отключится. –

1

что заставляет меня расстроился, что независимо от того, как я уничтожить клиента (процесс убийства и ...) метод ReadAsync сразу бросает исключение

Добро пожаловать в сеть (Socket) Программирование. Вы должны довольствоваться этими исключениями, поскольку очень редко приходится сталкиваться с исключениями в этих типах приложений. Это по дизайну.

Это ваше приложение, которое должно быть разработано в таком случае, что конечный пользователь получает хорошее сообщение, а не сообщение об исключениях.

... Метод ReadAsync немедленно генерирует исключение, которое в основном противоречит моим мыслям. (Насколько я прочитал обнаружение отключенного сокета TCP не должен быть легко)

Причина этого заключается в том:

TcpClient.Connected Property получает состояние подключения сокета клиента, как последний I/Вывода. Когда он возвращает false, клиентский сокет либо никогда не был подключен, либо больше не подключен.

Поскольку свойство Connected отражает только состояние соединения с самой последней операцией, вы должны попытаться отправить или получить сообщение для определения текущего состояния. После того как сообщение send failed, это свойство больше не возвращает true.

Обратите внимание, что это поведение по дизайну. Вы не можете надежно проверить состояние соединения, потому что в промежутке между тестом и отправкой/получением соединение могло быть потеряно. Ваш код должен предполагать, что сокет подключен и изящно обрабатывает неудачные передачи.

+0

спасибо за ответ, нормально ли, что ждут stream.ReadAsync() в этом бесконечном цикле? (я сделал это, чтобы продолжать слушать новые данные от клиента) – SHM

+0

@SHM - Да, все в порядке. Если клиент должен отправлять данные, которые много раз неизвестны заранее, тогда да, вы должны продолжать ждать и получать данные. Как только клиент закроет сокет, ваш цикл сломается, тем самым исключив исключение. –

+0

@SHM - Также внимательно прочитайте последние два абзаца моего ответа и с терпением. Это очень полезные слова. Удачи для вашего опыта в сетевом программировании. –

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