0

所以我开始使用套接字并异步读取它们。

第一个问题是这之间有什么区别:

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

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

另外,鉴于这是我的回调函数,为什么我阅读的示例对整个事情都有一个 try/catch,当然你只需要一个 try/catch 围绕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()了哪些函数以及它是如何管理的?

4

3 回答 3

2

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);
    }
}
于 2013-01-18T20:27:20.370 回答
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;
于 2013-01-18T18:01:17.583 回答
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.Dispose()后也Socket.Close()通话。如果您将侦听器套接字作为类的成员变量,请确保您实现IDisposable接口并正确处理您的套接字。

于 2013-01-18T19:02:21.010 回答