在C#中,使用SocketAsyncEventArgs Buffer处理部分接收消息的最佳方法是什么

时间:2018-05-08 13:06:15

标签: c# sockets asynchronous buffer

为了清理一些乱码并更好地理解SocketAsyncEventArgs类,我想知道从SocketAsyncEventArgs缓冲区重新组装部分接收消息的最有效技术是什么。

为了让您了解全局,我使用C#Socket客户端连接到TCP服务器,该客户端基本上会接收数据。收到的数据是基于消息的\ n字符分隔。

正如您可能已经意识到的那样,在使用ReceiveAsync方法时,这几乎是最后收到的消息未完成的证据,例如您必须找到最后一条完整消息的索引,复制不完整的消息缓冲区并将其保留为下一个接收缓冲区的开始,依此类推。

问题是,我希望从上层抽象出这个操作,并在_tmpBuffer中完成消息后立即调用ProcessReceiveDataImpl。我发现我的Buffer.BlockCopy不太可读(非常旧的代码( - :)但是无论如何我想知道你在这个典型的用例中做了什么?

重新组合邮件的代码:

public class SocketClient
{
    private const int _receiveBufferSize = 8192;
    private byte[] _remBuffer = new byte[2 * _receiveBufferSize];
    private byte[] _tmpBuffer = new byte[2 * _receiveBufferSize];

    private int _remBufferSize = 0;
    private int _tmpBufferSize = 0;

    private void ProcessReceiveData(SocketAsyncEventArgs e)
    {
        // the buffer to process
        byte[] curBuffer = e.Buffer;
        int curBufferSize = e.BytesTransferred;
        int curBufferOffset = e.Offset;
        int curBufferLastIndex = e.BytesTransferred - 1;
        int curBufferLastSplitIndex = int.MinValue;

        if (_remBufferSize > 0)
        {
            curBufferLastSplitIndex = GetLastSplitIndex(curBuffer, curBufferOffset, curBufferSize);

            if (curBufferLastSplitIndex != curBufferLastIndex)
            {
                // copy the remain + part of the current into tmp
                Buffer.BlockCopy(_remBuffer, 0, _tmpBuffer, 0, _remBufferSize);
                Buffer.BlockCopy(curBuffer, curBufferOffset, _tmpBuffer, _remBufferSize, curBufferLastSplitIndex + 1);
                _tmpBufferSize = _remBufferSize + curBufferLastSplitIndex + 1;

                ProcessReceiveDataImpl(_tmpBuffer, _tmpBufferSize);

                Buffer.BlockCopy(curBuffer, curBufferLastSplitIndex + 1, _remBuffer, 0, curBufferLastIndex - curBufferLastSplitIndex);
                _remBufferSize = curBufferLastIndex - curBufferLastSplitIndex;
            }
            else
            {
                // copy the remain +  entire current into tmp
                Buffer.BlockCopy(_remBuffer, 0, _tmpBuffer, 0, _remBufferSize);
                Buffer.BlockCopy(curBuffer, curBufferOffset, _tmpBuffer, _remBufferSize, curBufferSize);

                ProcessReceiveDataImpl(_tmpBuffer, _remBufferSize + curBufferSize);
                _remBufferSize = 0;
            }
        }
        else
        {
            curBufferLastSplitIndex = GetLastSplitIndex(curBuffer, curBufferOffset, curBufferSize);

            if (curBufferLastSplitIndex != curBufferLastIndex)
            {
                // we must copy the unused byte into remaining buffer
                _remBufferSize = curBufferLastIndex - curBufferLastSplitIndex;
                Buffer.BlockCopy(curBuffer, curBufferLastSplitIndex + 1, _remBuffer, 0, _remBufferSize);

                // process the msg 
                ProcessReceiveDataImpl(curBuffer, curBufferLastSplitIndex + 1);
            }
            else
            {
                // we can process the entire msg
                ProcessReceiveDataImpl(curBuffer, curBufferSize);
            }
        }
    }

    protected virtual void ProcessReceiveDataImpl(byte[] buffer, int bufferSize)
    {

    }

    private int GetLastSplitIndex(byte[] buffer, int offset, int bufferSize)
    {
        for (int i = offset + bufferSize - 1; i >= offset; i--)
        {
            if (buffer[i] == '\n')
            {
                return i;
            }
        }
        return -1;
    }
}

您的意见非常重要并受到赞赏! 谢谢!

更新
此外,而不是调用ProcessReceiveDataImpl并阻止进一步接收操作,将已完成的消息排队并将它们提供给消费者是否有用呢?

0 个答案:

没有答案