SendBuffer

원래벌레·2022년 8월 24일
0
post-custom-banner

🌞 SendBuffer?

  • SendBuffer에서 중요한 점은 SendBufferHelper 클래스 였다.
    SendBuffer의 경우 ReceiveBuffer와는 달리 쓰고 읽는 영역에 대하여 사용한 버퍼를 제거하고 앞으로 옮기는 Clear 메소드의 역할을 할 수가 없다.
    그이유는 Send는 여러 클라이언트에게 이루어지기 때문인데, 만약에 어떤 데이터를 A라는 사용자가 받았다는 이유로 삭제를 하게 되면 B라는 유저가 만약에 그 데이터를 사용 중이 었다면 크래쉬가 발생 할 것이다.

  • 그렇기 때문에 SendBuffer의 경우에는 큰 뭉탱이 버퍼를 선언하여 그곳에 데이터를 쌓는 식으로 만들게 된다.

  • 이러한 작업들은 여러 쓰레드에서 일어날 것이다. 그렇다면 같은 SendBuffer를 이용하기 때문에 lock을 걸어주지 않으면, 크래쉬가 일어날 것이다. 하지만 여기서 lock을 사용하게 되면, 성능상으로 느려지기 때문에 Helper 클래스에서 SendBuffer를 TLS영역으로 선언하여 각 쓰레드 별로 SendBuffer를 가져서 lock없이 데이터를 저장하고 Send하게끔 해주었다.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ServerCore
{
    public class SendBufferHelper
    {
        public static ThreadLocal<SendBuffer> CurrentBuffer = new ThreadLocal<SendBuffer>(() => { return null; });

        public static int ChunkSize { get; set; } = 4096 * 100;

        public static ArraySegment<byte> Open(int reserveSize)
        {
            if(CurrentBuffer.Value == null)
            {
                CurrentBuffer.Value = new SendBuffer(ChunkSize);
            }

            if (CurrentBuffer.Value.FreeSize < reserveSize)
            {
                CurrentBuffer.Value = new SendBuffer(ChunkSize);
            }

            return CurrentBuffer.Value.Open(reserveSize);
        }
        public static ArraySegment<byte> Close(int usedSize)
        {
            return CurrentBuffer.Value.Close(usedSize);
        }
    }
    public class SendBuffer
    {
        byte[] _buffer;
        int _usedSize = 0;

        public int FreeSize {  get { return _buffer.Length - _usedSize; } }

        public SendBuffer(int chunkSize)
        {
            _buffer = new byte[chunkSize];
        }

        public ArraySegment<byte> Open(int reserveSize)
        {
            if (reserveSize > FreeSize)
                return null;

            return new ArraySegment<byte>(_buffer, _usedSize, reserveSize);
        }

        public ArraySegment<byte> Close(int usedSize)
        {
            ArraySegment<byte> segment = new ArraySegment<byte>(_buffer, _usedSize, usedSize);
            _usedSize += usedSize;
            return segment;
        }
    }
}
public override void OnConnected(EndPoint endPoint)
        {
            Console.WriteLine($"OnConnected : {endPoint}");

            Knight knight = new Knight() { hp = 100, attack = 10 };

            ArraySegment<byte> openSegment = SendBufferHelper.Open(4096);

            byte[] buffer = BitConverter.GetBytes(knight.hp);
            byte[] buffer2 = BitConverter.GetBytes(knight.attack);
            Array.Copy(buffer, 0, openSegment.Array, openSegment.Offset, buffer.Length);
            Array.Copy(buffer2, 0, openSegment.Array, openSegment.Offset + buffer.Length, buffer2.Length);
            ArraySegment<byte> sendBuff = SendBufferHelper.Close(buffer.Length + buffer2.Length);



            Send(sendBuff);
            Thread.Sleep(1000);
            Disconnect();
        }
profile
학습한 내용을 담은 블로그 입니다.
post-custom-banner

0개의 댓글