서버 공부

[서버 공부]15.SendBuffer

myjeongjun 2025. 1. 15. 12:00

전에도 설명했듯이 Receive Buffer와는 다르게 SendBuffer는 사정이 좀 다르다고 한다,

이 개념이 아직 잘 와닫지는 않는다.

 

1.서버로부터 버퍼 예약 요청을 받는다. -> 버퍼가 아직 없거나 기존의 버퍼의 여유공간보다 더 큰 크기의 예약을하면 ChunkSize로 새로 할당해준다. 그렇지않은경우에는 기존 사용하던 버퍼를 계속사용한다.(최대한 같은 데이터들을 같은 버퍼에 눌러 담는느낌이다.)

 

2.보내고자 하는 데이터를 넣는다 (openSegment에 buffer, buffer2를 넣음)

 

3.Close()함수를 통해 지정해준 크기만큼의 데이터를 부분배열로 만들어서 보내준다.

 

이번강의를 듣고 SendBuffer의 특징으로는

1.openSegment는 데이터를 옮겨놓는 용도로만 사용하고있다. 아직 정확한 용도를 모르겟다.

 

2.SendBuffer는 Recv와 다르게 더 이상 다음 데이터를 담을 수없으면 그냥 새로 버퍼를 만들어버린다.(Recv는 포인터 2개를 둬서 한 개의 버퍼를 재사용햇다.)

 

3.ThreadLocal로 해놔서 SendBuffer는 스레드들의 개인공간에서 작업을 수행한다.

이 말은 여러개의 스레드가 이 작업에 접근하면 같은 내용이 여러번 보내지지 않나 라는 생각이들었다. 

->Send함수가 lock을 사용해서 구현되어잇어서 어차피 한 스레드밖에 실행못하고 한 번밖에 실행안하니 결과적으로 한 스레드에서만 작업하게된다.

 

        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);
            //openSegment보다 두개의 합이 크면 오류가날듯? 그래서 넉넉하게 잡아준거같음 openSegment는 일시적으로
            //쓰는중
            ArraySegment<byte> sendBuffer = SendBufferHelper.Close(buffer.Length + buffer2.Length);

            Send(sendBuffer);

            Thread.Sleep(1000);

            Disconnect();


        }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

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

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

        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);
        }
    }

    //receive버퍼는 세션마다 있음 send의 경우 
    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;
        }
    }
}

'서버 공부' 카테고리의 다른 글

[서버 공부]17.Packet Generator 1,2  (0) 2025.01.24
[서버 공부]16.PacketSession  (0) 2025.01.16
[서버 공부]14. RecvBuffer  (0) 2025.01.15
[서버 공부]12 Session 1,2  (0) 2025.01.12
[서버 공부]11. Listener  (0) 2025.01.12