Эквивалент Peek в C # асинхронных сокетов? - PullRequest
1 голос
/ 06 мая 2011

Я привык использовать синхронные сокеты.Чтобы иметь дело с сообщениями, которые еще не пришли полностью, я установил первые 4 байта равными ожидаемой длине сообщения.Тогда я бы использовал Socket.Receive (tcpRecv, 1024, SocketFlags.Peek);взглянуть на сообщение, не вытаскивая его из буфера.Если бы все это было там, я бы вытащил данные.Если бы не было, я бы оставил это там.Я разработал свой протокол так, чтобы никакое сообщение никогда не превышало 1024 байта.

В асинхронных сокетах я не вижу способа просмотреть данные.Есть ли способ сделать это?Есть ли лучший подход к этому, чем подсматривать за данными?

Спасибо.

-Ник

Ответы [ 2 ]

2 голосов
/ 06 мая 2011

Вам не нужно заглядывать: асинхронные сокеты .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

1 голос
/ 06 мая 2011

Ваш тот же поток данных работает без просмотра:

  • расписание чтения четырех байтов
  • когда он завершится, сохраните его в буфере и расшифруйте в длину "n"
  • график чтения длины "n" - 4
  • когда он завершится, добавьте его к четырем уже существующим байтам
  • расшифруйте ваше сообщение

Единственное отличие от просмотра - то, что вы должны сохранить четыре байта при их первоначальном чтении.

...