3

私は同期ソケットの使用に慣れています。まだ完全に到着していないメッセージを処理するために、最初の 4 バイトをメッセージの予想される長さに設定します。次にSocket.Receive(tcpRecv, 1024, SocketFlags.Peek);、メッセージをバッファから引き出すことなく、メッセージを確認するために使用します。すべてがそこにあれば、データを引き出します。そうでなければ、そこに置いておきます。メッセージが 1024 バイトを超えないようにプロトコルを設計しました。

非同期ソケットでは、データを覗く方法がわかりません。これを行う方法はありますか?データをのぞくよりも、これに対するより良いアプローチはありますか?

ありがとう。

-ニック

4

2 に答える 2

3

覗く必要はありません。.NET非同期ソケットを使用すると、覗くことなく同じタイプの機能を実現できます。私はあなたがこのようなものを探しているかもしれないと思います:

private void BeginReceive()
{
    if ( _clientState == EClientState.Receiving)
    {
        if (_asyncTask.BytesReceived != 0 && _asyncTask.TotalBytesReceived <= _maxPageSize)
        {
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            e.SetBuffer(_asyncTask.ReceiveBuffer, 0, _asyncTask.ReceiveBuffer.Length);
            e.Completed += new EventHandler<SocketAsyncEventArgs>(ReceiveCallback);
            e.UserToken = _asyncTask.Host;

            bool comletedAsync = false;
            try
            {
                comletedAsync = _socket.ReceiveAsync(e);
            }
            catch (SocketException se)
            {
                Console.WriteLine("Error receiving data from: " + _asyncTask.Host);
                Console.WriteLine("SocketException: {0} Error Code: {1}", se.Message, se.NativeErrorCode);

                ChangeState(EClientState.Failed);
            }

            if (!comletedAsync)
            {
                // The call completed synchronously so invoke the callback ourselves
                ReceiveCallback(this, e);
            }
        }
        else
        {
            //Console.WriteLine("Num bytes received: " + _asyncTask.TotalBytesReceived);
            ChangeState(EClientState.ReceiveDone);
        }
    }
}

コールバックを受け取ったら、別の受信をスケジュールできます。

private void ReceiveCallback(object sender, SocketAsyncEventArgs args)
{
    lock (_sync) // re-entrant lock
    {
        // Fast fail: should not be receiving data if the client
        // is not in a receiving state.
        if (_clientState == EClientState.Receiving)
        {
            String host = (String)args.UserToken;

            if (_asyncTask.Host == host && args.SocketError == SocketError.Success)
            {
                try
                {
                    Encoding encoding = Encoding.ASCII;
                    _asyncTask.BytesReceived = args.BytesTransferred;
                    _asyncTask.TotalBytesReceived += _asyncTask.BytesReceived;
                    _asyncTask.DocSource += encoding.GetString(_asyncTask.ReceiveBuffer, 0, _asyncTask.BytesReceived);

                    BeginReceive();
                }
                catch (SocketException e)
                {
                    Console.WriteLine("Error receiving data from: " + host);
                    Console.WriteLine("SocketException: {0} Error Code: {1}", e.Message, e.NativeErrorCode);

                    ChangeState(EClientState.Failed);
                }
            }
            else if (_asyncTask.Host != host)
            {
                Console.WriteLine("Warning: received a callback for {0}, but the client is currently working on {1}.",
                    host, _asyncTask.Host);
            }
            else
            {
                Console.WriteLine("Socket Error: {0} when receiving from {1}",
                   args.SocketError,
                   _asyncTask.Host);
                ChangeState(EClientState.Failed);
            }
        }
    }
}

私のブログで非同期クライアント全体を見ることができます:http://codesprout.blogspot.com/2011/04/asynchronous-http-client.html

于 2011-05-06T03:59:32.997 に答える
1

あなたの同じデータフローは、ピークなしで機能します:

  • 4 バイト読み取りをスケジュールする
  • 完了したら、バッファに保存し、長さ「n」にデコードします
  • 長さ "n" - 4 の読み取りをスケジュールする
  • 完了したら、すでにそこにある4バイトに追加します
  • あなたのメッセージを解読する

ピークとの唯一の違いは、最初に読み取るときに 4 バイトを保存する必要があることです。

于 2011-05-06T03:07:13.503 に答える