mardi 17 décembre 2019

Writting a efficient circular buffer for use with c# socket

My idea is to design and implement a efficient circular buffer to use with Socket server/client. I haven't seen this design anywhere. Its a bad ideia or something?

Here my initial design:

public class CircularBuffer
{
    // Create IReadOnlyList for use
    public IList<ArraySegment<Byte>> Buffers;
    // Track memory
    public int UsedMemory { get; private set; }
    public int FreeMemory { get; private set; }
    public int TotalMemory => UsedMemory + FreeMemory;
    // Create buffer
    public CircularBuffer(int memoryBlockSize = 512, int memoryBlockCount = 4);
    // Add more blocks to circular buffer
    public void IncreaseMemory(int memoryBlockSize = 512, int memoryBlockCount = 4);
    // When using IList<ArraySegment<Byte>> we need know how much data is written
    public void Advance(int count);
    // Read n bytes and free segments
    public byte[] Read(int count);
    // Peek n bytes
    public byte[] Peek(int count);
    // Free n bytes without reading (useful with Peek())
    public void Skip(int count);
}

Usage:

// Call BeginReceive of a Socket
Socket.BeginReceive(buffer.Buffers, SocketFlags.None, EndReceive, Socket);

// EndReceive method
private void EndReceive(IAsyncResult ar)
{
    var socket = (Socket)ar.AsyncState;
    var readedBytes = socket.EndReceive(ar);
    buffer.Advance(readedBytes); // Our class need to know how much data is written on buffer
    // This sample protocol use a 2byte header indicating the size of a incoming packet
    while(buffer.UsedMemory > 2) 
    {
        var header = buffer.Peek(2);
        var messageSize = BitConverter.ToUInt16(header, 0);
        if (buffer.UsedMemory - 2 < messageSize) break;
        buffer.Skip(2);
        var message = buffer.Read(messageSize);
        // Here we process/dispatch our received packet
    }
    // If our buffer is full after last loop our packet is bigger than the current capacity
    if(buffer.FreeMemory == 0)
    {
        buffer.IncreaseMemory();
    }
    // Start again
    socket.BeginReceive(buffer.Buffers, SocketFlags.None, EndReceive, socket);
}

Aucun commentaire:

Enregistrer un commentaire