简体   繁体   English

具有BeginReceive \\ EndReceive的异步套接字意外数据包

[英]Asynchronous socket unexpected packet with BeginReceive \ EndReceive

I need to receive an async message. 我需要接收异步消息。

In all messages, first 2 byte indicate the length of next byte array. 在所有消息中,前2个字节指示下一个字节数组的长度。 My problem is that in few case I receive unexpected packets. 我的问题是,在少数情况下,我会收到意外的数据包。

If I use Thread.Sleep(200) this problems does't happen, or happens rarely. 如果我使用Thread.Sleep(200)不会发生或很少发生此问题。

Where am I wrong? 我哪里错了?

protected void StartListening()
{
    StateObject state = new StateObject() { ProcessHeader = true };
    state.PrepareBuffer(HeaderLength);
    lock (_secureConnection)
        _secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
}

private void ReadCallback(IAsyncResult ar)
{
    if (_disposing)
        return;
    StateObject state = (StateObject)ar.AsyncState;
    try
    {
        lock (_secureConnection)
            _secureConnection.EndReceive(ar);
        if (state.ProcessHeader)
        {
            state.ProcessHeader = !state.ProcessHeader;
            var bodyLength = GetBodyLength(state.Buffer);
            //Thread.Sleep(200);
            state.CompleteMessage.AddRange(state.Buffer);
            state.PrepareBuffer(bodyLength);
            lock (_secureConnection)
                _secureConnection.BeginReceive(state.Buffer, 0, bodyLength, 0, new AsyncCallback(ReadCallback), state);
        }
        else
        {
            state.CompleteMessage.AddRange(state.Buffer);
            ProcessMessage(state.CompleteMessage); //process this message
            //Thread.Sleep(200);
            state.ProcessHeader = !state.ProcessHeader;
            state.CompleteMessage.Clear();
            state.PrepareBuffer(HeaderLength);
            lock (_secureConnection)
                _secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
        }
    }
    catch (Exception e)
    {
        Close(true);
    }
}

class StateObject
{
    public StateObject()
    {
        ProcessHeader = true;
    }
    public byte[] Buffer { get; private set; }
    public bool ProcessHeader { get; set; }
    public List<byte> CompleteMessage = new List<byte>();
    public void PrepareBuffer(int size)
    {
        Buffer = new byte[size];
    }
}

You are assuming that TCP is a message-based protocol. 您假设TCP是基于消息的协议。 It is a stream of bytes, though. 不过,它是字节流。 Your reads can read any amount greater than zero. 您的读数可以读取大于零的任何数量。 This is just like with a FileStream. 就像FileStream一样。 Files do not have messages, either. 文件也没有消息。

Your code has to deal with that fact. 您的代码必须处理这个事实。 Search for "TCP message framing". 搜索“ TCP消息框架”。

SOLUTION FOUND After a long time, i've written a good solution, I hope to help someone. 找到的解决方案经过很长一段时间,我写了一个很好的解决方案,希望对您有所帮助。 Thank you very much for your suggestions. 非常感谢您的建议。

    int HeaderLength = 2;
    int bodyLength;
    int bytesReceived;
    int totalBytesReceived;

    protected void StartListening()
    {
        StateObject state = new StateObject() { ProcessHeader = true };
        state.PrepareBuffer(HeaderLength);
        lock (_secureConnection)
            _secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
    }

    /// <summary>
    /// Reads the callback.
    /// 
    /// A message is in this form:
    /// 
    /// 2 bytes indicate the leght of body message (n)
    /// n bytes for body message
    /// 
    /// </summary>
    /// <param name="ar">IAsyncResult.</param>
    private void ReadCallback(IAsyncResult ar)
    {
        if (_disposing)
            return;
        StateObject state = (StateObject)ar.AsyncState;
        try
        {
            lock (_secureConnection)
                bytesReceived = _secureConnection.EndReceive(ar);

            if (state.ProcessHeader)    //In this phase I receive 2 bytes that indicate the total length of the next message
            {
                state.ProcessHeader = !state.ProcessHeader;
                bodyLength = GetBodyLength(state.Buffer);   //I interpret 2 bytes to know body message length
                state.CompleteMessage.AddRange(state.Buffer);
                state.PrepareBuffer(bodyLength);
                totalBytesReceived = bytesReceived = 0;
                lock (_secureConnection)
                    _secureConnection.BeginReceive(state.Buffer, 0, bodyLength, 0, new AsyncCallback(ReadCallback), state);
            }
            else    //In this phase I receive the message, with one or more recursive CallBack
            {
                state.CompleteMessage.AddRange(state.Buffer.ToList().GetRange(0, bytesReceived));

                totalBytesReceived += bytesReceived;
                int totalBytesMissing = bodyLength - totalBytesReceived;


                if (totalBytesReceived < bodyLength)
                {
                    state.PrepareBuffer(totalBytesMissing);
                    lock (_secureConnection)
                        _secureConnection.BeginReceive(state.Buffer, 0, totalBytesMissing, 0, new AsyncCallback(ReadCallback), state);
                    return;
                }
                //totalMessageLenght = body length plus first 2 bytes indicate body length
                int totalMessageLenght = bodyLength + 2;    

                var completeMessage = state.CompleteMessage.GetRange(0, totalMessageLenght).ToList();
                ProcessMessage(completeMessage);
                state.ProcessHeader = !state.ProcessHeader; //I prepare Callback to read 2 bytes indicate the total length of the next message

                state.CompleteMessage.Clear();
                state.PrepareBuffer(HeaderLength);
                lock (_secureConnection)
                    _secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
            }
        }
        catch (Exception e)
        {
            Close(true);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM