2013-01-18 175 views
0

所以我開始用套接字和異步讀取它們。異步套接字讀取

第一個問題是什麼這之間的區別:

socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult);

socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, ReadCallback, readResult);

此外,由於這是我的回調函數,爲什麼例子,我讀有一個嘗試/抓住整個事情,當然你只需要圍繞socket.EndReceive()呼叫嘗試/抓住?

public void ReadCallback(IAsyncResult ar) 
{ 
    try 
    { 
     var readResult = (SocketReadResult)ar.AsyncState; 
     var socket = readResult.Socket; 
     int bytesRead = socket.EndReceive(ar); 

     if (bytesRead > 0) 
     { 
      // There might be more data, so store the data received so far. 
      readResult.Text.Append(Encoding.ASCII.GetString(readResult.Buffer, 0, bytesRead)); 

      // Get the rest of the data. 
      socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult); 
     } 
     else 
     { 
      var newRead = new SocketReadResult(socket); 

      socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), newRead); 

      // All the data has arrived; put it in response. 
      if (readResult.Text.Length > 1) ((IMessageSender)this).RouteMessage(this, new MessageString(readResult.Text.ToString())); 
     } 
    } 
    catch (Exception e) 
    { 
     // TODO: manage this exception. 
    } 
} 

public struct SocketReadResult 
{ 
    StringBuilder Text; 
    Socket Socket; 
    byte[] Buffer; 

    public const int BufferSize = 1024; 

    public SocketReadResult(Socket s) 
    { 
     Socket = s; 
     Buffer = new byte[BufferSize]; 
     Text = new StringBuilder(); 
    } 
} 

最後所有的,你應該要正常關閉你叫socket.BeginReceive()後的監聽器,你叫什麼功能,以及它是如何管理的?

+0

至於爲什麼的try/catch是圍繞整個方法,ReadCallBack將異步可能在另一個線程或線程池進行。如果拋出一個異常,它將不會像您期望的那樣傳播回主線程​​,並且會最終導致進程崩潰。出於這個原因,你總是需要擁有任何可以在try/catch中完全包裝的獨立線程上運行的任何東西,因爲這是你最後一次正確處理錯誤的機會。 – Despertar

+0

不同的簽名和異常處理實際上是兩個單獨的問題。你不應該在同一個問題中提問。選擇一個或另一個,然後編輯另一個(如果需要,將其作爲新問題發佈)。 – Servy

+0

我沒有明白爲什麼你要讀取甚至當bytesRead == 0在其他部分? –

回答

1

socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult);

socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, ReadCallback, readResult);

都是一樣的東西,它同樣的事情

 //both are the same thing 
     button1.Click += new EventHandler(button1_Click); 
     button1.Click += button1_Click; 
+2

這裏的關鍵在於編譯器會推斷委託的類型,並以您的名義將第二個片段轉換爲第一個片段。 – Servy

0

在兩個電話之間的差別可以忽略不計,你可以認爲他們相當於。第二次調用將幫助編譯器爲您輸入推理,但這不會在IntelliSense和代碼自動完成之外引人注目。我個人使用第一種格式,因爲它更簡潔。

至於爲什麼try/catch不止是Socket.EndReceive()調用主要與其他局部變量的範圍有關。

考慮一下:

var state = result.AsyncState as SocketStateObject; 
var socket = state.Socket; 

try 
{ 
    var numberOfBytesRead = socket.EndReceive(result); 
} 
catch(SocketException ex) 
{ 
    // Handle the exception here. 
} 

// numberOfBytesRead is not accessible out here! 

try 
{ 
    if(socket.Connected) 
    socket.BeginReceive(...); // Receive again! 
} 
catch(SocketException ex) 
{ 
    // Handle the exception here too. 
} 

正如你可以在這裏看到,有幾個原因之一,更大的try/catch最好兩個獨立的,小的。

首先,局部變量僅在try的範圍內可用。您可以通過在try/catch區塊以外定義更高的值來解決該問題。其次,也許更重要的是與減少冗餘有關。由於您很可能在您的回撥中再次撥打Socket.BeginReceive(),因此將其置於相同的try/catch之下是有意義的。否則,你必須在兩個地方處理潛在的SocketException而不是一個地方。

至於優雅地關閉Socket,您可以使用Socket.Close()方法。通常套接字不會被重用,因此您可以通過false。但是,在撥打Socket.Close()之後,最好也撥打Socket.Dispose()。如果您將偵聽套接字作爲類的成員變量,請確保您實現了IDisposable接口並正確處理套接字。

+0

圍繞不會在try catch中拋出錯誤的代碼,它被認爲是不好的形式? – Cheetah

+0

一般而言,您應該編程以儘可能避免引發和捕獲異常。 'try/catch'模塊很好,但是性能成本會降低,即使從不拋出異常。捕獲的異常只會導致更高的處罰。例如,你應該使用不會拋出異常的'TryParse()'而不是'Parse()',它將會(例如:'int.TryParse()')。然而,有時例外是無法避免的,例如'Sockets',無論你的代碼有多好,網絡錯誤都不受控制。在這些情況下,你應該使用'try/catch'。 – Erik

1

a)它們是平等的。編譯器會爲你生成相同的代碼

B)如何編寫異步調用的一些推廣方法和,如果他們不阻塞調用者同步調用處理異常?

try 
{ 
    await socket.ConnectTaskAsync("www.google.com", 80); 

    await socket.SendTaskAsync(bytesToSend); 

    byte[] buf = new byte[0x8000]; 
    var bytesRead = await socket.ReceiveTaskAsync(buf, 0, buf.Length); 
} 
catch (Exception ex) 
{ 
    Console.WriteLine(ex.Message); 
} 

public static class SocketExtensions 
{ 
    public static Task ConnectTaskAsync(this Socket socket, string host, int port) 
    { 
     return Task.Factory.FromAsync(
        socket.BeginConnect(host, port, null, null), 
        socket.EndConnect); 
    } 

    public static Task<int> ReceiveTaskAsync(this Socket socket, 
              byte[] buffer, 
              int offset, 
              int count) 
    { 
     return Task.Factory.FromAsync<int>(
      socket.BeginReceive(buffer, offset, count, SocketFlags.None, null, socket), 
      socket.EndReceive); 
    } 


    public static Task SendTaskAsync(this Socket socket, byte[] buffer) 
    { 
     return Task.Factory.FromAsync<int>(
       socket.BeginSend(buffer,0,buffer.Length,SocketFlags.None, null, socket), 
       socket.EndSend); 
    } 
}