Pregunta

necesito para enviar varios mensajes entre una tubería con nombre nativo y un tubo llamado System.IO. Tengo el código para ambos extremos de esta comunicación desde el-En-Uno All marco de código (IPC y RPC).

Servidor:

SafePipeHandle hNamedPipe = null;

try { SECURITY_ATTRIBUTES sa = null;
sa = CreateNativePipeSecurity();

// Create the named pipe.
hNamedPipe = NativeMethod.CreateNamedPipe(
    Constants.FullPipeName,             // The unique pipe name.
    PipeOpenMode.PIPE_ACCESS_DUPLEX,    // The pipe is duplex
    PipeMode.PIPE_TYPE_MESSAGE |        // Message type pipe 
    PipeMode.PIPE_READMODE_MESSAGE |    // Message-read mode 
    PipeMode.PIPE_WAIT,                 // Blocking mode is on
    PIPE_UNLIMITED_INSTANCES,           // Max server instances
    1024,                 // Output buffer size
    1024,                 // Input buffer size
    NMPWAIT_USE_DEFAULT_WAIT,           // Time-out interval
    sa                                  // Pipe security attributes
);

if (hNamedPipe.IsInvalid)
{
    throw new Win32Exception();
}

Console.WriteLine("The named pipe ({0}) is created.", Constants.FullPipeName);

// Wait for the client to connect.
Console.WriteLine("Waiting for the client's connection...");
if (!NativeMethod.ConnectNamedPipe(hNamedPipe, IntPtr.Zero))
{
    if (Marshal.GetLastWin32Error() != ERROR_PIPE_CONNECTED)
    {
        throw new Win32Exception();
    }
}
Console.WriteLine("Client is connected.");

// 
// Receive a request from client.
// 

string message;
bool finishRead = false;
do
{
    byte[] bRequest = new byte[1024];
    int cbRequest = bRequest.Length, cbRead;

    finishRead = NativeMethod.ReadFile(
        hNamedPipe,             // Handle of the pipe
        bRequest,               // Buffer to receive data
        cbRequest,              // Size of buffer in bytes
        out cbRead,             // Number of bytes read 
        IntPtr.Zero             // Not overlapped 
        );

    if (!finishRead &&
        Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
    {
        throw new Win32Exception();
    }

    // Unicode-encode the received byte array and trim all the 
    // '\0' characters at the end.
    message = Encoding.Unicode.GetString(bRequest).TrimEnd('\0');
    Console.WriteLine("Receive {0} bytes from client: \"{1}\"", cbRead, message);
}
while (!finishRead);  // Repeat loop if ERROR_MORE_DATA

// 
// Send a response from server to client.
// 

message = "Goodbye\0";
byte[] bResponse = Encoding.Unicode.GetBytes(message);
int cbResponse = bResponse.Length, cbWritten;

if (!NativeMethod.WriteFile(
    hNamedPipe,                 // Handle of the pipe
    bResponse,                  // Message to be written
    cbResponse,                 // Number of bytes to write
    out cbWritten,              // Number of bytes written
    IntPtr.Zero                 // Not overlapped
    ))
{
    throw new Win32Exception();
}

Console.WriteLine("Send {0} bytes to client: \"{1}\"",
    cbWritten, message.TrimEnd('\0'));

// Flush the pipe to allow the client to read the pipe's contents 
// before disconnecting. Then disconnect the client's connection.
NativeMethod.FlushFileBuffers(hNamedPipe);
NativeMethod.DisconnectNamedPipe(hNamedPipe); 

} catch (Exception ex) { Console.WriteLine ( "El servidor lanza el error: {0}", ex.Message); } finalmente { si (hNamedPipe! = null) { hNamedPipe.Close (); hNamedPipe = null; } }

Cliente:

            NamedPipeClientStream pipeClient = null;

        try
        {
            // Try to open the named pipe identified by the pipe name.

            pipeClient = new NamedPipeClientStream(
                ".",         // The server name
                Constants.PipeName,           // The unique pipe name
                PipeDirection.InOut,        // The pipe is duplex
                PipeOptions.None            // No additional parameters
            );

            pipeClient.Connect(5000);
            MessageBox.Show(
                string.Format( "The named pipe ({0}) is connected.", Constants.PipeName )
            );

            pipeClient.ReadMode = PipeTransmissionMode.Message;

            // 
            // Send a request from client to server
            // 

            for ( int i = 0; i < 2; i++ ) {

                string message = "hello my pipe dream\0";
                byte[] bRequest = Encoding.Unicode.GetBytes( message );
                int cbRequest = bRequest.Length;

                pipeClient.Write( bRequest, 0, cbRequest );

                MessageBox.Show(
                    string.Format( "Send {0} bytes to server: \"{1}\"", cbRequest, message.TrimEnd( '\0' ) )
                );
            }

            //
            // Receive a response from server.
            // 

            do
            {
                byte[] bResponse = new byte[1024];
                int cbResponse = bResponse.Length, cbRead;

                cbRead = pipeClient.Read(bResponse, 0, cbResponse);

                // Unicode-encode the received byte array and trim all the 
                // '\0' characters at the end.
                string message = Encoding.Unicode.GetString(bResponse).TrimEnd('\0');
                Console.WriteLine("Receive {0} bytes from server: \"{1}\"",
                    cbRead, message);
            }
            while (!pipeClient.IsMessageComplete);

        }
        catch (Exception ex)
        {
            new ErrorDialog( ex ).ShowDialog();
        }
        finally
        {
            // Close the pipe.
            if (pipeClient != null)
            {
                pipeClient.Close();
                pipeClient = null;
            }
        }
    }

Como se puede ver en el bucle en la sección "Enviar una solicitud del cliente al servidor" anteriormente, estoy tratando de encontrar la manera de enviar varios mensajes al servidor. Veo que el código del servidor recorre hasta que los NativeMethod.ReadFile () devuelve el método verdaderos. Mi problema es que siempre se está volviendo realidad después se lee el primer mensaje, e ignorando el segundo mensaje Así que mi pregunta, en concreto, es: ¿qué tengo que hacer en el código de cliente para que este método devuelve falsos por lo que también se ve a buscar el segundo mensaje.

¿Fue útil?

Solución 2

Gracias, Chris, por dirigirme a la documentación. I hasta votado por su respuesta ya que el presupuesto que me incluidos llevaron a la respuesta que estaba buscando.

resulta que estaba confundido por el do / while en el código del servidor de "Recibir una solicitud del cliente" sección. Es decir, me parecía como si hubiera sido Recuperación de varios mensajes del cliente. Pero, de hecho, fue recuperando partes consecutivas del aviso individual. He actualizado que la sección de código de la siguiente manera.

// Receive a request from client.

string message = string.Empty;
bool finishRead = false;
do
{
    byte[] bRequest = new byte[1024];
    int cbRequest = bRequest.Length, cbRead;

    finishRead = NativeMethod.ReadFile(
        hNamedPipe,             // Handle of the pipe
        bRequest,               // Buffer to receive data
        cbRequest,              // Size of buffer in bytes
        out cbRead,             // Number of bytes read 
        IntPtr.Zero             // Not overlapped 
        );

    if (!finishRead &&
        Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
    {
        throw new Win32Exception();
    }

    // Unicode-encode the received byte array and trim all the 
    // '\0' characters at the end.
    message += Encoding.Unicode.GetString(bRequest).TrimEnd('\0');
}
while (!finishRead);  // Repeat loop if ERROR_MORE_DATA

Console.WriteLine( "Message received from client: \"{0}\"", message );

En cuanto a la delimitación de las múltiples "mensajes" dentro de la petición del cliente al servidor, probablemente sólo tiene que utilizar caracteres de nueva línea.

Otros consejos

No hay nada que el cliente puede hacer otra cosa que enviar a todos sus "mensajes" en una sola escritura en el tubo. Esto se debe a que, en el modo de mensaje, los mensajes están delimitados por la terminación de llamadas de escritura en el emisor, y su código de servidor lee explícitamente un solo mensaje (en el sentido modo de mensaje de tubería). Ver CreateNamedPipe y documentación API ReadFile :

Los datos se escriben a la tubería como una transmitir los mensajes. Las golosinas de tuberías los bytes escritos durante cada escritura operación como una unidad de mensaje.

Si una tubería con nombre está siendo leído en el modo de mensaje y el mensaje siguiente es más largo que el nNumberOfBytesToRead Especifica los parámetros, devoluciones ReadFile Devuelve FALSE y GetLastError ERROR_MORE_DATA. El resto de la mensaje puede ser leído por un subsiguiente llamar a la ReadFile o PeekNamedPipefunction.

Los posibles enfoques para trabajar con múltiples mensajes son:

  • definir algunos mayor encuadre nivel protocolo mediante el cual el cliente puede contar el servidor de la cantidad de mensajes para leer en cada intercambio de mensajes. El cliente a continuación, enviar una serie de mensajes algo como [cabecera de trama: count = 3] [mensaje 1] [mensaje 2] [mensaje 3], o alternativamente [mensaje 1] [mensaje 2] [mensaje 3] [tráiler encuadre: no más mensajes];
  • un servidor multiproceso en el que hay es un hilo dedicado continuamente lectura de mensajes desde el cliente, otras operaciones como la escritura mensajes al ser cliente hecho en otras roscas;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top