2010-06-04 68 views
2

我試圖使用兩個簡單的C#表單解決方案在我的Win-XP工作站上實現雙向命名管道通信。一個用於客戶端,另一個用於服務器。它們看起來幾乎完全相同,並使用NamedPipeServerStream和NamedPipeClientStream(.NET 3.5)。客戶端和服務器都通過PipeDirection.InOut無法獲取字符串數據以通過NamedPipeServerStream和NamedPipeClientStream

設置爲雙向通信啓動事件的順序是: 1)啓動服務器。它等待來自客戶端的連接。 2)啓動客戶端,它立即找到並連接到服務器。同樣,服務器完成與客戶端的連接。 3)客戶端和服務器都啓動它們的「讀取」線程,從而創建流讀取器的實例。這些線程然後調用ReadLn()並阻塞 - 等待數據。在所有情況下,autoflush都是如此。

然後,我使用streamwriter.WriteLn()將字符串數據從服務器發送到客戶端(反之亦然)。但是,執行永遠不會從該調用返回。我不知道爲什麼和任何見解會得到很好的接收。

我花了相當多的時間研究這個問題的所有,但我仍然失去了一些東西。

客戶端和服務器端的代碼片段所示:

SERVER:

private void ListenForClients() 
    { 
     // Only one server as this will be a 1-1 connection 
     m_pipeServerStream = new NamedPipeServerStream(PipeName, PipeDirection.InOut, 1); 

     // Wait for a client to connect 
     m_pipeServerStream.WaitForConnection(); 

     // Ccould not create handle - server probably not running 
     if (!m_pipeServerStream.IsConnected) 
      return; 

     // Create a stream writer which flushes after every write 
     m_pipeServerWriter = new StreamWriter(m_pipeServerStream); 
     m_pipeServerWriter.AutoFlush = true; 

     Connected = true; 

     // Start listening for messages 
     if (m_pipeServerStream.CanRead) 
     { 
      ReadThread = new Thread(new ParameterizedThreadStart(Read)); 
      ReadThread.Start(m_pipeServerStream); 
     } 
    } 

    /// <summary> 
    /// Reads data from the client 
    /// </summary> 
    /// <param name="serverObj"></param> 
    private void Read(object serverObj) 
    { 
     NamedPipeServerStream pipeStream = (NamedPipeServerStream)serverObj; 
     using (StreamReader sr = new StreamReader(pipeStream)) 
     { 
      while (true) 
      { 
       string buffer; 
       try 
       { 
        buffer = sr.ReadLine(); 
       } 
       catch 
       { 
        //read error has occurred 
        break; 
       } 

       //client has disconnected 
       if (buffer.Length == 0) 
        break; 

       //fire message received event 
       if (MessageReceived != null) 
       { 
        MessageReceived(buffer); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Sends a message to the connected client 
    /// </summary> 
    /// <param name="message">the message to send</param> 
    public void SendMessage(string message) 
    { 
     if (m_pipeServerWriter != null) 
     { 
      m_pipeServerWriter.WriteLine(message); 
      m_pipeServerWriter.Flush(); 
     } 
    } 

客戶:

private void ConnectToServer() 
    { 
     // Seek out the one server 
     m_pipeClientStream = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut); 

     // Connect to the waiting server 
     m_pipeClientStream.Connect(); 

     // Ccould not create handle - server probably not running 
     if (!m_pipeClientStream.IsConnected) 
      return; 

     // Create a stream writer which flushes after every write 
     m_pipeClientWriter = new StreamWriter(m_pipeClientStream); 
     m_pipeClientWriter.AutoFlush = true; 

     Connected = true; 

     // Start listening for messages 
     if (m_pipeClientStream.CanRead) 
     { 
      ReadThread = new Thread(new ParameterizedThreadStart(Read)); 
      ReadThread.Start(m_pipeClientStream); 
     } 
    } 

    /// <summary> 
    /// Reads data from the server 
    /// </summary> 
    private void Read(object serverObj) 
    { 
     NamedPipeClientStream pipeStream = (NamedPipeClientStream)serverObj; 
     using (StreamReader sr = new StreamReader(pipeStream)) 
     { 
      while (true) 
      { 
       string buffer; 
       try 
       { 
        buffer = sr.ReadLine(); 
       } 
       catch 
       { 
        //read error has occurred 
        break; 
       } 

       //client has disconnected 
       if (buffer.Length == 0) 
        break; 

       //fire message received event 
       if (MessageReceived != null) 
       { 
        MessageReceived(buffer); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Sends a message to the connected server 
    /// </summary> 
    /// <param name="message"></param> 
    public void SendMessage(string message) 
    { 
     if (m_pipeClientWriter != null) 
     { 
      m_pipeClientWriter.WriteLine(message); 
      m_pipeClientWriter.Flush(); 
     } 
    } 
+0

你有沒有弄清楚爲什麼要寫再也沒有回來? – Nikhil 2014-11-11 03:45:11

回答

2

我現在已經放棄了,搬到了使用的安全,明顯的技術兩個管道,每個通信方向一個。他們工作正常。

4

嘗試設置異步標誌上的流:

NamedPipeClientStream( 「」,PipeName,PipeDirection.InOut,PipeOptions.Asynchronous);

0

我不確定這是否有幫助,但我也遇到同樣的問題。首先,我不知道爲什麼對m_pipeServerStream.IsConnected的任何引用都會破壞管道。我用一個簡單的MessageBox.Show(m_pipeServerStream.IsConnected.ToString())測試了這一點,並打破了我的管道!其次,另一個奇怪的是,如果您使用的是雙工命名管道,則您的streamreader調用將永遠不會返回。您將需要手動讀取像這樣

const int BufferSize = 4096; 
    Decoder decoder = Encoding.UTF8.GetDecoder(); 
    StringBuilder msg = new StringBuilder(); 
    char[] chars = new char[BufferSize]; 
    byte[] bytes = new byte[BufferSize]; 
    int numBytes = 0; 
    MessageBox.Show("before do while loop"); 
    numBytes = pipeServer.Read(bytes, 0, BufferSize); 
    if (numBytes > 0) 
    { 
     int numChars = decoder.GetCharCount(bytes, 0, numBytes); 
     decoder.GetChars(bytes, 0, numBytes, chars, 0, false); 
     msg.Append(chars, 0, numChars); 
    } 

    MessageBox.Show(numBytes.ToString() + " " + msg.ToString()); 

    MessageBox.Show("Finished reading, now starting writing"); 
    using (StreamWriter swr = new StreamWriter(pipeServer)) 
    { 
     MessageBox.Show("Sending ok back"); 
     swr.WriteLine("OK"); 
     pipeServer.WaitForPipeDrain(); 
    } 

無論如何,這似乎並不喜歡的StreamReader的行爲,但這對於現在的工作......我這一關這個環節http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/23dc2951-8b59-48e4-89fe-d2b435db48c6/

我沒有遵循每一個步驟,因爲我只是需要找出它爲什麼會一直停留在StreamReader.ReadLine()。它不是從這個函數返回的。 StreamWriter似乎沒有這個問題。

我實際上是在原生dll和託管windows服務之間進行通信。想象一下,當我發現它是問題的管理部分時,我感到驚訝,而不是非管理部分,因爲他們在msdn中有這樣的好例子......

0

我並不擅長命名管道或匿名管道,但我會竭盡全力幫助別人,即使你有解決問題的辦法。

客戶端服務器通信是思考如何實現此過程的最佳方式。

服務器啓動並偵聽連接 - >客戶端啓動到服務器的連接 - >服務器接受連接 - >客戶端發出請求 - >服務器發出響應 - >連接是關閉。

enter image description here

服務器啓動並監聽連接:

try 
{ 
namedPipeServerStream = new NamedPipeServerStream(PipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); 

// Wait for a connection here... 
namedPipeServerStream.BeginWaitForConnection(new AsyncCallback(ConnectionCallBack), namedPipeServerStream); 
} 
catch (Exception ex) 
{ 
Debug.WriteLine(ex.Message); 
} 

客戶端連接,然後發出請求:

try 
{ 
namedPipeClientStream = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous); 

// Connect with timeout... 
namedPipeClientStream.Connect(TimeOut); 

byte[] buffer = Encoding.UTF8.GetBytes(DataToSend); 
namedPipeClientStream.BeginWrite(buffer, 0, buffer.Length, ConnectionCallBack, namedPipeClientStream); 
} 
catch (TimeoutException ex) 
{ 
Debug.WriteLine(ex.Message); 
} 

ConnectionCallBack是異步回調。這種方法(這是對客戶端)是其中連接管理:

private void ConnectionCallBack(IAsyncResult iAsyncResult) 
{ 
try 
{ 
// Get the pipe 
NamedPipeClientStream namedPipeClientStream = (NamedPipeClientStream)iAsyncResult.AsyncState; 

// End the write 
namedPipeClientStream.EndWrite(iAsyncResult); 
namedPipeClientStream.Flush(); 

// Get Server Response... 
GetServerResponse(namedPipeClientStream); 

// Flush Data and Close Pipe... 
namedPipeClientStream.Flush(); 
namedPipeClientStream.Close(); 
namedPipeClientStream.Dispose(); 
} 
catch (Exception ex) 
{ 
Debug.WriteLine(ex.Message); 
} 
} 

服務器處理客戶機請求與制定一個響應,並將其發送:

// Response Methods... 
public void SendResponse(string ServerResponse) 
{ 
try 
{ 
// Fill Buffer with Server Response Data... 
byte[] Buffer = Encoding.UTF8.GetBytes(ServerResponse); 

// Begin Async Write to the Pipe... 
namedPipeServerStream.BeginWrite(Buffer, 0, Buffer.Length, SendResponseCallBack, namedPipeServerStream); 
} 
catch (Exception ex) 
{ 
Debug.WriteLine(ex.Message); 
} 
} 

private void SendResponseCallBack(IAsyncResult iAsyncResult) 
{ 
try 
{ 
// Get the Pipe Handle... 
NamedPipeServerStream namedPipeServerStream = (NamedPipeServerStream)iAsyncResult.AsyncState; 

// End the Write and Flush... 
namedPipeServerStream.EndWrite(iAsyncResult); 
namedPipeServerStream.Flush(); 

// Close the Connection and Dispose... 
namedPipeServerStream.Close(); 
namedPipeServerStream.Dispose(); 
} 
catch (Exception ex) 
{ 
Debug.WriteLine(ex.Message); 
} 
} 

這是從客戶端調用請求處理程序:

private void ClientRequestHandler(string clientRequest) 
{ 
try 
{ 
if (this.InvokeRequired) 
{ 
this.Invoke(new InvokedDelegate(ClientRequestHandler), clientRequest); 
} 
else 
{ 
ProcessClientRequest(clientRequest); 
} 
} 
catch (Exception ex) 
{ 
Debug.WriteLine(ex.Message); 
} 
} 

private void ProcessClientRequest(string clientRequest) 
{ 
// Display the Client Request... 
richTextBox1.Text = clientRequest; 

PipeServer.SendResponse("Server has received Client Request at: " + DateTime.Now); 
} 

客戶端已經啓動了一個到服務器的連接,點在哪裏的異步回調方法參見就是:

// Get Server Response... 
GetServerResponse(namedPipeClientStream); 

連接仍處於打開狀態。客戶已請求和管道沖洗,並準備好客戶端讀取上面提到的服務器響應:

private void GetServerResponse(NamedPipeClientStream namedPipeClientStream) 
{ 
byte[] buffer = new byte[255]; 
namedPipeClientStream.Read(buffer, 0, buffer.Length); 

// Convert byte buffer to string 
string ResponseData = Encoding.UTF8.GetString(buffer, 0, buffer.Length); 

// Pass message back to calling form 
ServerResponse.Invoke(ResponseData); 
} 

接收到響應,然後連接被重新同步,然後關閉準備好客戶端啓動另一個連接。

代碼比這更復雜一點,但本質上這是它的工作原理。啓動連接時,請使用它。一旦你關閉它,然後嘗試重新初始化它,你將需要等待一段時間才能正確處理它,否則你會得到各種信號量錯誤等等。當你不需要的時候不要吸菸!

請參閱:Code Project - C# Async Named Pipes for an excellent example