2016-10-04 5 views
3

Я использую асинхронные каналы, и в какой-то момент и сервер, и клиент ждут друг друга и ничего не делают. Вот мой код:C# async named pipes wait for ever

Сервер:

var buffer = new byte[BufferSize]; 
using (var server = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous)) 
{ 
    // Wait for client. 
    Logger.Trace("Waiting for connection ..."); 
    var asyncResult = server.BeginWaitForConnection(a => { }, null); 
    while (true) 
    { 
      await Task.Delay(MillisecondsDelay); 
      if (asyncResult.IsCompleted) break; 
     } 
     server.EndWaitForConnection(asyncResult); 
     Logger.Trace("Connection established."); 


     using (var sr = new StreamReader(server)) 
     using (var sw = new StreamWriter(server)) 
     { 
      // Send work. 
      Logger.Trace("Sending operations..."); 
      await sw.WriteAsync(JsonConvert.SerializeObject(data)); 
      await sw.FlushAsync(); 
      server.WaitForPipeDrain(); 

       // Wait for response. 
       var bytesRead = await server.ReadAsync(buffer, 0, buffer.Length); 

     ..... 

Клиент:

 // Read data from the pipe... 
using (var client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous)) 
{ 
     Logger.Trace("Connecting to server..."); 
     client.Connect(); 
     Logger.Trace("Connected."); 

     using (var sr = new StreamReader(client)) 
     using (var sw = new StreamWriter(client)) 
     { 
      // Read operations. 
      Logger.Trace("Waiting operations..."); 
      var text = await sr.ReadToEndAsync(); 
     ..... 

Бревна, что я беру такие:

2016-10-04 16:09:51.5375 => (TRACE) | MyController.Execute : Waiting for connection ... | 
2016-10-04 16:09:52.0706 => (TRACE) | MyController+<Execute>d__5.MoveNext : Connection established. | 
2016-10-04 16:09:52.0706 => (TRACE) | MyController+<Execute>d__5.MoveNext : Sending operations... | 

и:

2016-10-04 16:09:51.8486 => (TRACE) | EXE.Program.Process : Connecting to server... | 
2016-10-04 16:09:51.8696 => (TRACE) | EXE.Program.Process : Connected. | 
2016-10-04 16:09:51.8696 => (TRACE) | EXE.Program.Process : Waiting operations... | 

А потом ничего!

После этого он кажется запертым.

Я думаю, что я должен использовать WaitForPipeDrain() после каждой записи сервером или клиентом, и я это делаю, но, похоже, это не помогает.

Операция чтения клиента никогда не возвращается.

Любые идеи кто-нибудь?

+1

Когда вы говорите «ReadToEndAsync», как читатель потока знает, что он в конце? Неужели он все еще тупик, если вы используете 'ReadAsync'? – DavidG

+0

@DavidG Мое предположение заключалось в том, что * был * конец потока (где нет других данных для чтения), несмотря на то, что поток не закрыт. Поэтому я считаю, что он сможет прочитать содержимое с текущей позиции до конца текущего размера потока. И я также просто попытался использовать 'ReadLineAsync()' вместо этого, и он все еще имеет ту же проблему. 'ReadAsync' читает байтовые массивы, поэтому для этого потребуется больше рефакторинга ... – user2173353

+0

Ну,' ReadLine' подразумевает, что существует строка, которая может отсутствовать. Вы также можете попробовать использовать 'ConfigureAwait (false)' на ваших ожиданиях. – DavidG

ответ

4

Я думаю, проблема в методе ReadToEndAsync. Для определения скорости передачи StreamReader не существует способа. Например, это может быть медленное соединение и отправлено только половину данных. Как правило, в этих ситуациях вам нужно придумать свой «протокол» для отправки данных. Существуют различные методы: вот пара:

  1. Ждите символа терминатора. Много раз я видел символ ASCII 4, используемый для этого, поскольку он означает «EOT» (end of transmission). Однако это основано на предположении, что ваше сообщение - это не просто поток двоичных данных, который может также содержать этот символ. Вместо этого вы можете сделать терминатор последовательностью, несколько символов, которые почти никогда не будут отображаться в потоке.

  2. Префикс сообщения с длиной данных, которые вы собираетесь отправить. Например, первые 4 байта: всегда длина, после захвата этого, теперь вы знаете, сколько читать.