在《CLR via C#》的27.2小節中使用了命名管道的內容,上一篇是一個使用命名管道的例子,在《CLR via C#》中同樣有一個命名管道的例子(使用異步),具體內容如下:
服務器端的代碼:
internal sealed class PipeServer{
//聲明一個命名管道
private readonly NamedPipeServerStream m_pipe = new NamedPipeServerStream(
"Echo",PipeDirection.InOut,-1,PipeTransmissionMode.Message,
PipeOptions.Asynchronous|PipeOptions.WriteThrough);
public PipeServer(){
m_pipe.BeginWaitForConnection(
}
//定義當客戶端連接後的回調方法
private void ClientConnected(IAsyncResult result){
new PipeServer();
//APM的結束
m_pipe.EndWaitForConnection(result);
byte[] data = new byte[1000];
m_pipe.BeginRead(data,0,data.length,GotRequest,data);
}
//當數據讀取完畢後的回調方法
private void GotRequest(IAsyncResult result){
//EndRead方法返回已經讀取內容的字節數。若返回值爲零,則代表到達流的末尾
int bytesread=m_pipe.EndRead(result);
byte[] data=(byte[])result.AsyncState;
data=Encoding.UTF8.GetBytes(
Encoding.UTF8.GetString(data,0,bytesread).ToUpper().ToCharArray());
m_pipe.BeginWrite(data,0,data.Length,WriteDone,null);
}
private void WriteDone(IAsyncResult result){
m_pipe.EndWrite(result);
m_pipe.Close();
}
}
通過上面的這個例子,可以看到APM(Asynchronous Programming Model)的編寫模式,在方法的內部,以Endxxx爲開始,以BeginXXX爲結束,在兩者之間是相關的內容處理。
參數說明
對BeginXXX中方法的參數說明:方法的前三個參數是正常的,第四個參數是AsyncCallback,該委託的定義如下:
public delegate void AsyncCallback(IAsyncResult ar)
可以將IAsyncResult
看成是IRP的唯一標示。其唯一標示了一個I/O請求,系統在將請求放入驅動程序的隊列中,並返回IAsyncResult對象的一個引用。
IAsyncResult
是一個接口,而該接口具有幾個屬性,而實現了該接口的類也一定會存在這幾個屬性。這幾個屬性的具體定義如下:
IAsyncResult的AsyncState就可以用於數據傳輸,由beginxxx傳入到endxxx中。下面是客戶端的代碼
internal sealed class PipeClient{
private readonly NamedPipeClientStream m_pipe;
public PipeClient(string serverName,string message)
{
m_pipe=new NamedPipeClientStream(serverName,"Echo",PipeDirection.Inout,PipeOptions.Asynchronous|PipeOptions.WriteThrough);
m_pipe.Connect();
//必須先連接,之後才能設定ReadMode
m_pipe.ReadMode=PipeTransmissionMode.Message;
byte[] output=Encoding.UTF8.GetBytes(message);
m_pipe.BeginWrite(output,0,output.Length,WriteDone,null);
}
private void WriteDone(IAsyncResult result){
m_pipe.EndWrite(result);
byte[] data=new byte[1000];
m_pipe.BeginRead(data,0,data.Length,GotResponse,data);
}
private void GotResponse(IAsyncResult result){
int bytesRead = m_pipe.EndRead(result);
byte[] data=(byte[])result.AsyncState;
Console.WriteLine("服務器的返回值"+Encoding.UTF8.GetString(data,0,data.Length));
m_pipe.Close();
}
}
如何使用服務器端和客戶端的程序
使用服務器端的代碼如下:
public static void Main(){
for(int i=0;i<Environment.ProcessorCount;i++){
new PipeServer();
}
Console.WriteLine("回車結束服務器程序");
Console.ReadLine();
}
使用客戶端的代碼如下
public static void Main(){
for(int i=0;i<100;i++)
new PipeClient(".","請求"+i);
Console.ReadLine();
}
以上的代碼均來自《CLR via C#》的27.2小節。代碼很簡單,抄錄很麻煩。肩膀都酸了。
小節
APM與其他正常的代碼沒有任何的差別,不管是異常處理還是其他方面,基本上一模一樣。只有一個例外,就是在使用beginxxx和endxxx時略有差別。與多線程相比較,基本上沒有什麼太大的花樣。
在27.2的開頭,反而是講了APM的關鍵信息
1、所有派生自system.io.stream並與硬件通信的類(包括filestream和networkstream)都提供APM
2、system.net.dns類提供了幾個方法
3、system.net.sockets.socket類中提供符合APM編程方式的方法
另外,所有委託都定義了一個begininvoke方法。
總的來說,APM編碼方式是一種考慮了系統穩定性的編碼方式。其作用是讓系統更加穩定。與正常使用的方法沒有多大的差別。