Equivalent of Peek in C# async sockets?

杀马特。学长 韩版系。学妹 提交于 2020-01-06 01:57:48

问题


I'm used to using synchronous sockets. In order to deal with messages that have not completely arrived yet, I'd set the first 4 bytes to be the expected length of the message. Then I'd use Socket.Receive(tcpRecv, 1024, SocketFlags.Peek); to take a look at the message without pulling it off the buffer. If all of it was there, I'd pull the data. If it wasn't, I'd leave it there. I had designed my protocol so that no message would ever be greater than 1024 bytes.

In asynchronous sockets, I don't see a way to peek at the data. Is there a way to do this? Is there a better approach to this than peeking at the data?

Thanks.

-Nick


回答1:


You don't need to peek: .NET asynchronous sockets allow you to achieve the same type of functionality without peeking. I think you might be looking for something like this:

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

When you get the callback you can schedule another receive:

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

You can see the entire asynchronous client on my blog: http://codesprout.blogspot.com/2011/04/asynchronous-http-client.html




回答2:


Your same data flow works without peeking:

  • schedule a four byte read
  • when it completes, save it in the buffer and decode it into length "n"
  • schedule a read of length "n" - 4
  • when it completes, append it to the four bytes already there
  • decode your message

The only difference from peeking is that you have to save the four bytes when you initially read them.



来源:https://stackoverflow.com/questions/5906243/equivalent-of-peek-in-c-sharp-async-sockets

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!