2010-12-18 3 views
2

네이티브 명명 된 파이프와 System.IO 명명 된 파이프간에 여러 메시지를 보내야합니다. All-In-One Code Framework (IPC 및 RPC)에서이 통신의 양 끝 코드를 얻었습니다.네이티브 명명 된 파이프와 System.IO 명명 된 파이프간에 여러 메시지 보내기

는 서버 :

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

} 캐치 (예외 예) { Console.WriteLine는 ("서버 오류 발생 : {0}", ex.Message을); } finally { if (hNamedPipe! = null) { hNamedPipe.Close(); hNamedPipe = null; } }

클라이언트 :

  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; 
      } 
     } 
    } 

, 나는 여러 보내는 방법을 알아 내려고 노력하고있어 당신은 위의 "클라이언트에서 서버로 요청을 보내기"섹션에서 for 루프에서 볼 수 있듯이 메시지를 서버에 보냅니다. NativeMethod.ReadFile() 메서드가 true를 반환 할 때까지 서버 코드가 반복되는 것을 볼 수 있습니다. 내 문제는 항상 첫 번째 메시지를 읽은 후 true 반환하는 및 두 번째 메시지를 무시합니다 그래서 내 질문에 구체적으로,이 코드는이 메서드는 false를 반환 할 수 있도록 클라이언트 코드에서 할 필요가 그래서 다음 이동합니다. 두 번째 메시지.

답변

0

감사합니다, Chris, 저에게 문서를 가르쳐 주셔서 감사합니다. 포함 된 견적이 나에게 내가 찾던 대답으로 인도 한 이후 나는 당신의 대답에 대해 찬성표를 던졌습니다.

나는 서버 코드의 "클라이언트 요청 수신"섹션에서 do/while 루프를 혼동했다. 즉, 클라이언트에서 여러 메시지를 검색하는 것처럼 보였습니다. 그러나 실제로는 단일 메시지의 연속 부분을 검색하고있었습니다. 그 코드 섹션을 다음과 같이 업데이트했습니다.서버에 클라이언트의 요청에서, 나는 아마 줄 바꿈 문자를 사용합니다 "메시지"다중를 구분에 관해서는

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

.

1

클라이언트가 파이프에 대한 단일 쓰기로 모든 "메시지"를 보내는 것 외에 다른 작업은 할 수 없습니다. 이는 메시지 모드에서 보낸 사람이 쓰기 호출을 완료하여 메시지를 구분하고 서버 코드가 파이프 메시지 모드 의미에서 하나의 메시지 만 명시 적으로 읽게되기 때문입니다. 있습니다

Data is written to the pipe as a stream of messages. The pipe treats the bytes written during each write operation as a message unit.

If a named pipe is being read in message mode and the next message is longer than the nNumberOfBytesToRead parameter specifies, ReadFile returns FALSE and GetLastError returns ERROR_MORE_DATA. The remainder of the message can be read by a subsequent call to the ReadFile or PeekNamedPipefunction.

가능한 방법은 여러 메시지와 함께 작업 :

  • 이 을 읽는 방법을 많은 메시지 클라이언트가 서버를 말할 수있는 프로토콜을 프레임 일부 높은 수준을 정의 CreateNamedPipeReadFile API 설명서를 참조하십시오 각 메시지 교환에서 클라이언트는 [framing header : count = 3] [message 1] [message 2] [message 3] 또는 다른 방법으로 [message 1] [message 2] [message 3]와 같은 일련의 메시지를 보냅니다. [framing trailer : 더 이상 메시지 없음];
  • 이 는 클라이언트의 전용 스레드가 계속 읽기 메시지 인 다중 스레드 서버가 클라이언트에 다시 메시지를 작성하는 등의 다른 작업이 다른 스레드에서 수행되고;