2016-09-13 2 views
0

Хорошо, у меня есть код для представления. Вот метод расширения для объекта NetworkStream.Await не дает результата

public async static Task<byte[]> ReadDataAsync(this NetworkStream clientStream) 
{ 
    byte[] data = {}; 

    var buffer = new byte[1024]; 
    if (clientStream.CanRead) 
    { 
     using (var ms = new MemoryStream()) 
     { 
      try 
      { 
       int bytesRead; 
       while (clientStream.DataAvailable && 
        (bytesRead = await clientStream.ReadAsync(buffer, 0, buffer.Length)) > 0) 
       { 
        await ms.WriteAsync(buffer, 0, bytesRead); 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.ToString()); 
       return data; 
      } 

      data = ms.ToArray(); 
     } 
    } 
    else 
    { 
     Console.WriteLine("Closing clientStream."); 
     clientStream.Close(); 
    } 
    return data; 
} 

И код, где я пытаюсь назвать этот метод.

public async static Task Preform(Socket client) 
{ 
    var stream = new NetworkStream(client); 
    var data = await stream.ReadDataAsync(); 
    var message = await MessageFabrique.DeserializeMessage(data); 

    ServerCollections.Instance.ServerIssueQueue.Add(new ServerIssue 
    { 
     Message = message, 
     ClientStream = stream 
    }); 
} 

ReadDataAsync метод всегда возвращает меня в пустой массив. И в тот момент, когда я пытаюсь десериализовать данные, есть исключение - потому что data[0]. Пожалуйста, помогите мне. Почему это происходит, если awaitгарантирует мне результат, когда это необходимо?

+0

Вы уверены, что не получаете и исключение в своем блоке catch? Он вернет данные [0]. –

+0

Вы работаете в консольном приложении? – EJoshuaS

+0

@ Sergey.quixoticaxis.Ivanov, №. Я не ловил исключений в этой области. –

ответ

4

clientStream.DataAvailable не означает, что данные могут появиться в будущем. Это означает, что данные доступны прямо сейчас для чтения. Избавьтесь от него и просто прочитайте, чтение будет блокироваться до тех пор, пока данные не появятся или не вернутся 0, когда поток достигнет конца.

+0

Thnx, Scot. Я попробую. –

+0

Это работа сейчас. –

0

ответ Скотта является правильным, но .Net уже заботится о вас ...

Вы могли бы рассмотреть Stream.CopyToAsync

await clientStream.CopyToAsync(ms) 

для кода со значительно меньшим количеством мест, чтобы пойти не так.

+0

Могу ли я это сделать без использования цикла, «пока» в этом случае? –

+0

@TrumanStarr, да, 'CopyToAsync' скопирует * все * потока на другой в одну операцию. – spender

+0

danke для подсказки! –

0

В дополнение к другим ответам вы также можете создать контекст синхронизации. См. this article.

Резюме состоит в том, что async/await работает по-разному в консольных приложениях, чем в пользовательском интерфейсе. Приложения WPF и WebForms по умолчанию имеют контекст синхронизации, но консольных приложений этого нет. Результат (который на самом деле замечательно «плохо рекламируется» в документации) заключается в том, что поведение async/await равно , а менее предсказуемо в консольном приложении, чем в приложении UI, и что это может заставить его работать не так », как рекламируется "при определенных обстоятельствах.

Например, в приложении пользовательского интерфейса «асинхронный» не обязательно означает, что код работает в фоновом потоке. Это эквивалент «вернись ко мне позже, когда я буду готов». Как аналог, подумайте о том, чтобы пойти съесть с 10 людьми: когда приходит официант, первый человек, которого он просит, не готов. Два плохих решения здесь состоят в том, чтобы: а) привлечь второго официанта либо дождаться, когда первый парень станет готов, либо возьмет остальные 9 человек), либо б) дождаться, пока первый парень не начнет принимать заказы. Оптимальным является принятие других 9 заказов людей, а затем возвращение к первому парню, надеясь, что он будет готов к этому времени. Рискуя упростить это в основном, как async работает в пользовательском интерфейсе (если вы явно не помещаете код в фоновый поток с чем-то вроде Task.Run). Однако в консольном приложении, когда вы используете async, нет никакой гарантии относительно того, где код действительно будет работать.

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

+0

Я запускаю коммуникационный сервер-клиент по обратному вызову в 'Task.Run (() => ...). ConfigureAwait (false)'. В этом случае я думаю, что это важно. Thanx. –

+0

@TrumanStarr. Не обязательно четкое преимущество в производительности, если вы установите его на фоновый поток, если все, что вы делаете, ждет результата. – EJoshuaS

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