system.io.Pipelines长度字段基于TCP解码



我正在尝试将代码从dotnetty转换为system.io..io.pipelines。在dotnetty中,我正在利用Length FieldBasedeCoder解码TCP消息,其中前两个字节代表一个指示整个消息长度的整数。

我看到的所有演示都依赖基于字符串的EOL指标。我觉得这应该很容易,但是它逃脱了我如何抓住前两个字节,然后是x字节的数量,如长度前缀所示。

以下是David Fowler的TCPecho服务器的一个示例。如果前两个字节指示消息大小,而不是指示Message结束的EOL字符?

,我该如何重写以解析消息?
 private static async Task ReadPipeAsync(Socket socket, PipeReader reader)
    {
        while (true)
        {
            ReadResult result = await reader.ReadAsync();
            ReadOnlySequence<byte> buffer = result.Buffer;
            SequencePosition? position = null;
            do
            {
                // Find the EOL
                position = buffer.PositionOf((byte)'n');
                if (position != null)
                {
                    var line = buffer.Slice(0, position.Value);
                    ProcessLine(socket, line);
                    // This is equivalent to position + 1
                    var next = buffer.GetPosition(1, position.Value);
                    // Skip what we've already processed including n
                    buffer = buffer.Slice(next);
                }
            }
            while (position != null);
            // We sliced the buffer until no more data could be processed
            // Tell the PipeReader how much we consumed and how much we left to process
            reader.AdvanceTo(buffer.Start, buffer.End);
            if (result.IsCompleted)
            {
                break;
            }
        }
        reader.Complete();
    }

这就是我最终得到的:

private const int lengthPrefixSize = 2; // number of bytes in the length prefix
private static ushort ParseLengthPrefix(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer);
private static ushort ParseLengthPrefix(in ReadOnlySequence<byte> buffer)
{
    if (buffer.First.Length >= lengthPrefixSize)
        return ParseLengthPrefix(buffer.First.Span.Slice(0, lengthPrefixSize));
    Span<byte> lengthPrefixBytes = stackalloc byte[lengthPrefixSize];
    buffer.Slice(0, lengthPrefixSize).CopyTo(lengthPrefixBytes);
    return ParseLengthPrefix(lengthPrefixBytes);
}
private static async Task ReadPipeAsync(Socket socket, PipeReader reader)
{
    ushort? lengthPrefix = null;
    while (true)
    {
        ReadResult result = await reader.ReadAsync();
        ReadOnlySequence<byte> buffer = result.Buffer;
        while (true)
        {
            if (lengthPrefix == null)
            {
                // If we don't have enough for the length prefix, then wait for more data.
                if (buffer.Length < lengthPrefixSize)
                    break;
                // Read and parse the length prefix
                lengthPrefix = ParseLengthPrefix(buffer);
                buffer = buffer.Slice(lengthPrefixSize);
            }
            // If we haven't read the entire packet yet, then wait.
            if (buffer.Length < lengthPrefix.Value)
                break;
            // Read the data packet
            var line = buffer.Slice(0, lengthPrefix.Value);
            ProcessLine(socket, line);
            buffer = buffer.Slice(lengthPrefix.Value);
            lengthPrefix = null;
        }
        // We sliced the buffer until no more data could be processed
        // Tell the PipeReader how much we consumed and how much we left to process
        reader.AdvanceTo(buffer.Start, buffer.End);
        if (result.IsCompleted)
        {
            break;
        }
    }
    reader.Complete();
}

此解决方案确实具有长度前缀缓冲区,但是仅当长度前缀跨越跨度时才使用。我认为有一个SequenceReader<T>来了,尽管在长度前缀(很少的字节和没有缓冲区分配(的情况下,差异可能是最小的。

可能是最小的。

最新更新