2011-07-15 8 views
7

Al usar C# NamedPipeServerStream, en caso de que un cliente no envíe ningún mensaje final-pattern (como \ r \ n cuando el servidor lee con ReadLine()) NamedPipeServerStream Read métodos esperará para siempre y no Abort Los métodos() o Interupt() funcionarán en ese hilo.Tiempo de espera de lectura de servidor de canalizaciones con nombre

desde:
1) no Stream.ReadTimeout soportado para NamedPipeServerStream
2) Abort() o Interupt() no funciona en hilo
3) NamedPipeServerStream.Disconnect() de trabajo inferior
No está claro , ¿cómo configurar el tiempo de espera en las operaciones de lectura de NamedPipeServerStream?


Déjame presentarte un ejemplo. La especificación de IPC requiere un intercambio de cadenas terminadas en \ 0. Un cliente envía un mensaje, el servidor procesa el mensaje y como 'obligatorio' envía una respuesta. Si el cliente no envía \ 0 al final (el cliente no es nuestro, entonces no podemos garantizar la corrección de su funcionamiento), el método Read esperará por siempre y el cliente (ya que no lo controlamos) puede esperar para siempre para una respuesta también.

El siguiente es un ejemplo simplificado de una implementación:

public void RestartServer() 
    { 
     _pipeServerThread.Interrupt(); //doesn't affect Read wait 
     _pipeServerThread.Abort();  //doesn't affect Read wait 
    } 

    private void PipeServerRun(object o) //runs on _pipeServerThread 
    { 
     _pipeServer = new NamedPipeServerStream(_pipeName, InOut, 100, 
         PipeTransmissionMode.Message, PipeOptions.WriteThrough); 
     //_pipeServer.ReadTimeout = 100; //System.InvalidOperationException: Timeouts are not supporte d on this stream. 

     // Wait for a client to connect 
     while (true) 
     { 
      _pipeServer.WaitForConnection(); 
      string request = ReadPipeString(); 
      //... process request, send response and disconnect 
     } 
    } 

    /// <summary> 
    /// Read a \0 terminated string from the pipe 
    /// </summary> 
    private string ReadPipeString() 
    { 
     StringBuilder builder = new StringBuilder(); 
     var streamReader = new StreamReader(_pipeServer); 

     while (true) 
     { 
      //read next byte 
      char[] chars = new char[1]; 
      streamReader.Read(chars, 0, 1); // <- This will wait forever if no \0 and no more data from client 

      if (chars[0] == '\0') return builder.ToString(); 
      builder.Append(chars[0]); 
     } 
    } 

Entonces, ¿cómo poner el tiempo en NamedPipeServerStream operaciones de lectura?

Respuesta

2

Dado que está ejecutando la tubería en el modo de mensaje, primero debe leer todo el mensaje en una memoria intermedia byte[] o una secuencia de memoria y luego decidir si es válido y decodificarlo. Los mensajes de tubería tienen una duración definida. No se puede recuperar explícitamente, pero aparece cuando está leyendo desde un canal en modo mensaje. Win32 ReadFile falla con ERROR_MORE_DATA si todavía hay bytes no leídos en el mensaje, luego devuelve TRUE para indicar que el mensaje ha finalizado. Después de esto, una llamada al ReadFile se bloqueará hasta que haya un nuevo mensaje disponible. StreamReader, naturalmente, no sabe nada de esto y bloquea su hilo.

Actualización: Para implementar los tiempos de espera, utilice la E/S asíncrona (Stream.BeginRead). StreamReader no es compatible con esto directamente. Si es absolutamente necesario utilizarlo, escribir un flujo de envoltura que implementará Read en términos de BeginRead en el flujo de los tiempos de espera y de apoyo subyacentes, cancelación etc.

+0

Gracias, pero desafortunadamente no es la respuesta a mi pregunta. C# NamedPipeServerStream tiene un indicador IsMessageComplete que, según creo, depende del personal ERROR_MORE_DATA. Pero sucede que se establece en verdadero antes del final real del mensaje. Fue uno de los primeros que comprobamos. Si el cliente usa TransactNamedPipe parece que funciona, pero cuando uno usa la función C# NamedPipeClient o Write en WinApi, IsMessageComplete se puede configurar como verdadero antes de que se complete el mensaje. Creo que es, una vez más, debido a la naturaleza del transmisor de Stream. – MajesticRa

+0

Sí, pero ¿por qué ejecutar la tubería en modo mensaje? En el modo de mensaje, se crea un mensaje de canalización para cada llamada de Win32 'Write'. Si sus clientes no se adhieren a esta convención, el modo de mensaje no tiene sentido. (Por cierto, ¿los clientes realmente configuran el extremo del cliente de la tubería al modo de mensaje?) –

+1

Lamentablemente, el mundo no es perfecto y solo tengo las especificaciones. Nuestro cliente de prueba está en modo de mensaje. Pero no podemos garantizar esto sobre los clientes existentes. Parece que hay un problema con BeginRead también, pero sigo experimentando con él. – MajesticRa

1

intente configurar NamedPipeServerStream.ReadMode y/o .TransmissionMode a byte. Independientemente de esto, debe utilizar los métodos BeginRead/EndRead disponibles con NamedPipeServerStream. De esta manera puede implementar la lógica de tiempo de espera usted mismo.

Cuestiones relacionadas