2016-01-08 4 views
2

Прошу прощения за недостаток знаний о задачах и Async.TcpClient; NetworkStream; ReadAsync; C#

Использование класса TcpClient я создаю связь с доступным сервером:

void async RunClientAsync() 
{ 
    TcpClient client = new TcpClient(); 
    try 
    { 
     await client.ConnectAsync(IPAddress.Parse("1.1.1.1"), 8889); 
     Task.Start(() => ReadClientAsync(client)); 
    } 
    catch (Exception ex) 
    { 
     HandleException(ex); 
    } 
} 

// ----- 

void async ReadClientAsync(TcpClient client) 
{ 
    byte[] bf = new byte[2048]; 
    try 
    { 
     while(true) 
     { 
      int br = await client.NetworkStream().ReadAsync(); 
      if (br > 0) 
      { 
       HandleInboundData(bf, br); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     HandleException(ex); 
    } 
} 

хелперной метода HandleException (Exception ех) и HandleInboundData (байты [] буфер, внутр длиной) будут выполнять взятую на себя задачу.

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

ReadClientAsync (клиент TcpClient) является очевидным сбоем, поскольку ReadAsync всегда будет возвращать 0 байтов, если данных нет.

Как подойти к написанию ReadClientAsync с помощью async/task, чтобы предотвратить ситуацию с занятой петлей? Раньше я использовал BeginRead/EndRead, который работал нормально. Будет ли это решение в этом конкретном случае?

Спасибо,

+0

Благодарим вас за комментарий. Это из записи MSDN для ReadAsync: «Задача, представляющая операцию асинхронного чтения.Значение параметра TResult содержит общее количество байтов, считанных в буфере. Значение результата может быть меньше количества запрошенных байтов, если количество доступных в настоящее время байтов меньше запрошенного числа, или оно может быть 0 (ноль), если конец потока достигнут. «Я понял конец потока чтобы не было данных в потоке для чтения. – Jam

+0

Понял. Спасибо, Луаан. По-моему, я понимаю, в чем проблема. – Jam

ответ

4

Нет, это не то, как работает TCP.

NetworkStream считается находящимся в состоянии «конец потока», когда другая сторона инициировала (возможное одностороннее) завершение работы. Вот когда ReadAsync (или Read, если на то пошло) возвращает ноль - ни в каком другом случае.

Документацию MSDN можно легко понять, главным образом потому, что вы смотрите на неправильную документацию. NetworkStream не переопределяет ReadAsync (нет причин для этого), поэтому вы действительно смотрите документацию на общий номер Stream.ReadAsync. Напротив, в документации для NetworkStream.Read указано:

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

Обратите внимание на заключительное предложение, в котором говорится о том, что это означает для NetworkStream как «конец потока». Вот как TCP-соединения закрыты.

Ваш ответ на это обычно должен заключаться в том, чтобы отключить соединение с другой стороны - return из вашего вспомогательного метода и очистить разъем. В любом случае, не повторяйте снова while (true) - вы просто получите бесконечный цикл, который ест 100% вашего процессора.

Если вы хотите несколько указателей на то, как обращаться с асинхронными сокетами C# с await, посмотрите на мой образец на https://github.com/Luaancz/Networking/tree/master/Networking%20Part%202. Обратите внимание на отказ от ответственности - это никоим образом не готово к производству. Но он решает некоторые из очень распространенных ошибок, которые люди делают при реализации TCP-связи.

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