Domanda

ho bisogno di inviare più messaggi tra una named pipe nativa e un tubo System.IO di nome. Ho ottenuto il codice per entrambe le estremità di questa comunicazione della All-In-One Codice quadro (IPC e RPC).

Server:

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 ( "Il server genera l'errore: {0}", ex.Message); } finalmente { if (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;
            }
        }
    }

Come si può vedere dal ciclo for nella sezione "Invia una richiesta dal client al server" di cui sopra, sto cercando di capire come inviare più messaggi al server. Vedo che il codice del server scorre fino a quando il metodo NativeMethod.ReadFile () restituisce true. Il mio problema è che si è sempre tornando vero dopo il primo messaggio viene letto, e ignorando il secondo messaggio Quindi la mia domanda, in particolare, è quello che ho bisogno di fare nel codice client in modo che il metodo restituisce false in modo da allora andrà get il secondo messaggio.

È stato utile?

Soluzione 2

Grazie, Chris, per me indicando la documentazione. I up-votato la tua risposta dal momento che la citazione che mi Incluso portato alla risposta che cercavo.

Si scopre che sono stato solo confuso dal do / while nel codice del server "Ricevi una richiesta da parte del cliente" sezione. Cioè, sembrava a me come è stato recuperando più messaggi dal client. Ma in realtà, è stato recuperando parti consecutivi del singolo messaggio. Ho aggiornato quella sezione codice come segue.

// 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 );

Per quanto riguarda la delimitazione delle molteplici "messaggi" all'interno la richiesta del client al server, io probabilmente basta usare caratteri di nuova riga.

Altri suggerimenti

Non c'è niente il cliente può fare altro che inviare tutti i suoi "messaggi" in una singola scrittura al tubo. Questo perché, in modalità di messaggio, i messaggi sono delimitati dal completamento di chiamate di scrittura presso il mittente, e il codice server legge esplicitamente un solo messaggio (in modalità di senso messaggio pipe). Vedere CreateNamedPipe e ReadFile API documentazione:

I dati vengono scritti al tubo come flusso di messaggi. I tubi tratta i byte scritti nel corso di ogni scrittura funzionamento come unità di messaggio.

Se una named pipe viene letto in modalità messaggio e il messaggio successivo è più lungo del nNumberOfBytesToRead specifica dei parametri, resi ReadFile restituisce FALSE e GetLastError ERROR_MORE_DATA. Il resto della messaggio può essere letto da un successivo chiamare al ReadFile o PeekNamedPipefunction.

I possibili approcci al lavoro con più messaggi sono:

  • definire alcuni inquadramento di livello superiore protocollo con il quale il cliente può dire il server quanti messaggi da leggere in ogni interscambio messaggio. Il cliente avrebbe quindi inviare una serie di messaggi qualcosa di simile [intestazione inquadratura: count = 3] [messaggio 1] [messaggio 2] [messaggio 3], o, in alternativa [messaggio 1] [messaggio 2] [messaggio 3] [trailer inquadratura: Niente più messaggi];
  • un server multithread in cui vi è un filo dedicato continuamente la lettura dei messaggi da parte del cliente, altre operazioni come la scrittura messaggi avanti all'essere cliente fatto su altri thread;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top