2013-01-18 146 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); 
    } 
}