2014-04-25 107 views
0

目前,我已經使用演示代碼http://msdn.microsoft.com/en-us/library/bb546085.aspx實現了命名管道。而不是同步客戶端;不過,我想讓它異步。下面是我的實現,其中主要的程序使StartClientNamedPipeListening(通話):async NamedPipeClientStream實現反饋

/// <summary> 
    /// Buffer where received bytes or bytes received are stored 
    /// </summary> 
    private byte[] _byteBuffer = null; 

    /// <summary> 
    /// Callback result for reading data from the named pipe 
    /// </summary> 
    private IAsyncResult _pipeResult; 

    /// <summary> 
    /// Named object to send and receive data to and from watchdog 
    /// </summary> 
    NamedPipeClientStream _pipeClient; 

    /// <summary> 
    /// Notifies waiting threads that an event has occurred 
    /// </summary> 
    protected ManualResetEvent _pipeReadDone = new ManualResetEvent(false); 

    private object _pipeState = new object(); 

    private void StartClientNamedPipeListening() 
    { 
      // open and then close the gate as soon as after one thread passed, 
      // i.e., put the event into a non-signaled, or closed, state: 
      _pipeReadDone.Reset(); 

      // Reads the data coming in from the pipe and call the 
      // thread safe delegate to get the data received. 
      _byteBuffer = new Byte[50]; 
      _pipeResult = _pipeClient.BeginRead(_byteBuffer, 0, 
       _byteBuffer.Length, PipeReadCallback, _pipeState); 

      // worker thread block in here (waiting for... 
      // _pipeReadDone.Set()), i.e., wait for the door to be opened 
      _pipeReadDone.WaitOne();    
    } 

    private void PipeReadCallback(IAsyncResult ar) 
    { 
     int bytesRead = 0; 

     // if port serial is open and.. 
     if (_pipeClient.IsConnected) 
     { 
      // the stream can read then.. 
      if (_pipeClient.CanRead) 
      { 
       // wait for asynchronous read to be completed 
       bytesRead = _pipeClient.EndRead(ar); 
      } 
     } 

     if (bytesRead > 0) 
     { 
      StreamString ss = new StreamString(_pipeClient); 
      // Validate the server's signature string 
      if (ss.ReadString() == "I am the one true server!") 
      { 
       // The client security token is sent with the first write. 
       // Send the name of the file whose contents are returned 
       // by the server. 
       ss.WriteString(@"C:\Temp\namedpipestring.txt"); 

       // Print the file to the screen. 
       Console.WriteLine(ss.ReadString(), false); 
      } 
      else 
      { 
       Console.WriteLine("Server could not be verified."); 
      } 

      // put the event into a signaled, or open, state: 
      // open gate for next data 
      _pipeReadDone.Set(); 

      // Start waiting for the next watchdog message 
      StartClientNamedPipeListening(); 
     } 
    } 

該工程的實施,根據我的測試;然而,我想知道,我是否做了一些明顯的禁忌?有沒有人對如何更好地實施它有任何建議? TIA。

+0

這似乎很適合代碼審查:http://codereview.stackexchange.com/ – attila

+0

我不認爲我有權移動它。你知道如何將這篇文章轉移到該論壇嗎? – Roger

+1

當然,有一個明顯的缺陷。它*完全*無法使用BeginRead(),然後阻塞,直到收到響應。只需調用Read()。如果你的意思是異步的,那麼這個並不緊密,這意味着「不要等待」。 –

回答

0

以下是我如何修改代碼以使其異步工作。我不知道爲什麼我認爲我需要ManualResetEvent:

/// <summary> 
    /// Buffer where received bytes or bytes received are stored 
    /// </summary> 
    private byte[] _byteBuffer = null; 

    /// <summary> 
    /// Callback result for reading data from the named pipe 
    /// </summary> 
    private IAsyncResult _pipeResult; 

    /// <summary> 
    /// Named object to send and receive data to and from watchdog 
    /// </summary> 
    NamedPipeClientStream _pipeClient; 

    private object _pipeState = new object(); 

    private void StartClientNamedPipeListening() 
    { 
      _pipeClient = new NamedPipeClientStream(".", "testpipe", 
       PipeDirection.InOut, PipeOptions.Asynchronous, 
       TokenImpersonationLevel.Impersonation); 
      _pipeClient.Connect(); 
      // Reads the data coming in from the pipe and call the 
      // thread safe delegate to get the data received. 
      _byteBuffer = new Byte[50]; 
      _pipeResult = _pipeClient.BeginRead(_byteBuffer, 0, 
       _byteBuffer.Length, PipeReadCallback, _pipeState);  
    } 

    private void PipeReadCallback(IAsyncResult ar) 
    { 
     int bytesRead = 0; 

     // if port serial is open and.. 
     if (_pipeClient.IsConnected) 
     { 
      // the stream can read then.. 
      if (_pipeClient.CanRead) 
      { 
       // wait for asynchronous read to be completed 
       bytesRead = _pipeClient.EndRead(ar); 
      } 
     } 

     if (bytesRead > 0) 
     { 
      StreamString ss = new StreamString(_pipeClient); 
      // Validate the server's signature string 
      if (ss.ReadString() == "I am the one true server!") 
      { 
       // The client security token is sent with the first write. 
       // Send the name of the file whose contents are returned 
       // by the server. 
       ss.WriteString(@"C:\Temp\namedpipestring.txt"); 

       // Print the file to the screen. 
       Console.WriteLine(ss.ReadString(), false); 
      } 
      else 
      { 
       Console.WriteLine("Server could not be verified."); 
      } 

      // Start waiting for the next watchdog message 
      StartClientNamedPipeListening(); 
     } 
    } 

謝謝,漢斯。

+1

爲什麼不使用TPL和'Task.Factory.FromAsync'? – Noseratio

+0

我不熟悉Task.Factory,但感謝您的建議。我得看看它。 – Roger

+0

實際上,一個首選的方法就是在'async' /'await'中使用'NamedPipeClientStream.ReadAsync'和'NamedPipeClientStream.WriteAsync'。 – Noseratio