C# 异步套接字读取

C# 异步套接字读取,c#,sockets,asynchronous,C#,Sockets,Asynchronous,因此,我开始使用套接字并异步读取它们 第一个问题是这两者之间有什么区别: socket.BeginReceive(readResult.Buffer,0,SocketReadResult.BufferSize,0,新异步回调(ReadCallback),readResult) 及 socket.BeginReceive(readResult.Buffer,0,SocketReadResult.BufferSize,0,ReadCallback,readResult) 还有,既然这是我的回调函数,

因此,我开始使用套接字并异步读取它们

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

socket.BeginReceive(readResult.Buffer,0,SocketReadResult.BufferSize,0,新异步回调(ReadCallback),readResult)

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

还有,既然这是我的回调函数,为什么我读的示例中有一个try/catch,当然您只需要对
socket.EndReceive()调用进行try/catch

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()
后优雅地关闭侦听器,您将调用哪些函数以及如何管理这些函数?

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;
socket.BeginReceive(readResult.Buffer,0,SocketReadResult.BufferSize,0,新异步回调(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;

这两个调用之间的差别是可以忽略的,你可以认为它们是等价的。第二个调用将帮助编译器为您进行类型推断,但在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.Close()
方法。通常,套接字从不重用,因此您可以为此传递
false
。但是,最好在调用
Socket.Close()
之后再调用
Socket.Dispose()
。如果将侦听器套接字保存为类的成员变量,请确保您实现了 IDSistabs接口,并正确地处理了Socket。

两个调用之间的差异是可以忽略的,并且可以考虑它们的等价性。第二个调用将帮助编译器为您进行类型推断,但在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.Close()
方法。通常,套接字从不重用,因此您可以为此传递
false
。但是,最好在调用
Socket.Close()
之后再调用
Socket.Dispose()
。如果您将侦听器套接字作为类的成员变量,请确保实现IDisposable接口并正确处理套接字。

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);
}

公共静态类SocketExtensions
{
公共静态任务ConnectTaskAsync(此套接字、字符串主机、int端口)
{
返回Task.Factory.fromsync(
socket.BeginConnect(主机、端口、null、null),
插座(终端连接);
}
公共静态任务ReceiveTaskAsync(此套接字,
字节[]缓冲区,
整数偏移,
整数计数)
{
返回Task.Factory.fromsync(
socket.BeginReceive(缓冲区、偏移量、计数、SocketFlags.None、null、套接字),
插座(接收端);
}
公共静态任务SendTaskAsync(此套接字,字节[]缓冲区)
{
返回Task.Factory.fromsync(
socket.BeginSend(buffer,0,buffer.Length,SocketFlags.None,null,socket),
socket.EndSend);
}
}
a)他们