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 があるの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

2 つの呼び出しの違いはごくわずかであり、同等と見なすことができます。2 番目の呼び出しは、コンパイラが型を推論するのに役立ちますが、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.
}

ここでわかるように、1 つの大きな方try/catchが 2 つの別々の小さなものよりも望ましい理由がいくつかあります。

まず、ローカル変数は のスコープ内でのみ使用できますtrytry/catchブロックの外側でより高く定義することで、これを解決できます。

第二に、そしておそらくもっと重要なことは、冗長性を減らすことです。コールバックで再度呼び出す可能性が高いためSocket.BeginReceive()、同じ の下に置くのが理にかなっていますtry/catch。そうしないと、自分の可能性SocketExceptionを 1 か所ではなく 2 か所で処理する必要があります。

優雅に閉じるにはSocket、メソッドを使用できますSocket.Close()。通常、ソケットは再利用されないため、それを渡すことができますfalse。ただし、通話Socket.Dispose()後に通話することもお勧めしSocket.Close()ます。リスナー ソケットをクラスのメンバー変数として保持している場合は、必ずIDisposableインターフェイスを実装し、ソケットを適切に破棄してください。

于 2013-01-18T19:02:21.010 に答える