В C #, как лучше всего обрабатывать частично полученные сообщения с помощью буфера SocketAsyncEventArgs - PullRequest
0 голосов
/ 08 мая 2018

Чтобы очистить некоторый беспорядочный код и лучше понять класс SocketAsyncEventArgs, я бы хотел узнать, какой наиболее эффективный метод повторной сборки частично полученных сообщений из буферов SocketAsyncEventArgs.

Чтобы дать вам общую картину, я подключен к TCP-серверу с помощью клиента сокета C #, который, по сути, будет получать данные. Полученные данные основаны на сообщениях, разделенных символом \ n.

Как вы, вероятно, уже знаете, при использовании метода ReceiveAsync, это почти уверенность в том, что последнее полученное сообщение будет неполным, например, вам нужно будет найти индекс последнего полного сообщения, скопировать неполное раздел буфера и оставьте его в качестве начала для следующего полученного буфера и т. д.

Дело в том, что я хочу абстрагировать эту операцию от верхнего уровня и вызвать ProcessReceiveDataImpl, как только я получу завершенные сообщения в _tmpBuffer. Я обнаружил, что мой 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 и блокировать дальнейшие операции приема, будет ли полезно ставить завершенные сообщения в очередь и делать их доступными для потребителя?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...