SendBuffer

이승한·2023년 12월 30일
0

Server

목록 보기
4/4

SendBuffer

이전에 만든 RecvBuffer에 이어서 SendBuffer를 만들어 보자


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

[/][/] [/][u] [/][/] [/][/] [/][/]
int _usedSize = 0;

  1. FreeSize : 남은 공간

  2. Open
    2-1. 최대 할당 크기
    2-2. 남은 공간이 남아있으면 reserveSize만큼 할당
    2-3. 예약공간(reserveSize)보다 남은 공간(FreeSize)가 적으면 buffer은 고갈된 것이니 null 리턴

  3. Close
    3-1. 실제 내가 사용한 사이즈
    3-2. 위의 Open에서 3바이트를 할당했지만 실제로는 2바이트만 사용했으면 남은 공간을 반환
    3-3. 유효범위 리턴


public class SendBufferHelper
{
    //전역으로 선언하면 SendBuffer은 처음 할당한 크기에서 사용이 가능하면 재사용을 할 건데
    //멀티 쓰레드환경에서는 경합이 될것이다.
    //그래서 이전에 배운 전역이지만 나의 쓰레드에서 고유하게 사용가능한 전역 선언방법
    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)
        {
            //null이면 한번도 사용하지 않은 상태이니 생성
            CurrentBuffer.Value = new SendBuffer(ChunkSize);
        }

        if (CurrentBuffer.Value.FreeSize < reserveSize)
        {
            //지금 남은 공간이 예약공간보다 적으면 새로운 버퍼로 갈아끼움
            CurrentBuffer.Value = new SendBuffer(ChunkSize);
        }

        //여기까지 조건문을 통과했으면 남은공간이 있다는거니까 Open
        return CurrentBuffer.Value.Open(reserveSize);
    }
    public static ArraySegment<byte> Close(int usedSize)
    {
        return CurrentBuffer.Value.Close(usedSize);
    }
}

사용 코드 흐름 ( 완벽하지 않음)

//클라이언트 -> 서버
class Packet()
{
	public ushort size;
	public ushort packetId;
}
class PlayerInfoReq : Packet
{
    public long playerId;
}

class ServerSession : Session
{
	public override void OnConnected(EndPoint endPoint)
    {
    	Console.WriteLine($"OnConnected ! {endPoint}");
        
    	PlayerInfoReq packet = new PlayerInfoReq() {packetId = (ushort)PacketID.PlayerInfoReq, playerId = 1001};
        
        ArraySegment<byte> s = SendBufferHelper.Open(4096);
        ushort count = 0;
		bool success = true;
        count += 2;
		success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), packet.packetId);
		count += 2;
		success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset + count, s.Count - count), packet.playerId);
		count += 8;
        success &= BitConverter.TryWriteBytes(new Span<byte>(s.Array, s.Offset, s.Count), count);
        
        ArraySegment<byte> sendBuff = SendBufferHelper.Close(count);
        
		if(success)
    		Send(sendBuff);
    }
}

0개의 댓글