서버 공부

[서버 공부]14. RecvBuffer

myjeongjun 2025. 1. 15. 00:32

지금까지 만들어놓은 RecvBuffer에서 문제점은 TCP방식으로 받고있다보니 패킷으로 데이터를 받게되었을때 일부가 손실된채로 올수가있다. 그것에 대한 처리가 전혀 없기때문에 나중에 패킷으로 데이터를 받을때를 대비해서 시스템을 구축 해놓고자한다.

 

recvArgs.SetBuffer(new byte[1024],0,1024); 

기존이 코드는 매번 새로운byte배열을 불러주었다. 당연히 비효율적이다.

 

만들고자 하는것을 설명하자면

 

1.일종의 2개의 포인터를 두는것이다.

_readPosition : 읽기를 시도했을때 _readPosition과 writePosition사이에 있는 값들을 읽어줌 즉, 배열에 유효한 데이터의 시작점

_writePosition :배열에서 유효한 데이터의 끝점이라고 보면된다.

 

2.위의 2개를 가지고서 

DataSize : 유효한 데이터 크기

FreeSize : Receive할 수있는 데이터 크기

 

ReadSegment: 버퍼에서 유효한 데이터가 들어있는 부분배열

WriteSegment : 버퍼에서 추가로 받을 수 있는 부분배열

같은 변수를 만든다.

 

3.함수 3개도 만들어주는데Clear(): 버퍼의 크기는 정해져있기때문에(여기서는 1024바이트로 설정) _readPosition_writePosition의 위치를 다시 초기화 해주지않으면 어느 시점부터는 버퍼의 크기를 넘어간다.

 

이때 상황에 맞춰서 초기화를 해줘야하는데상황 1 : _readPosition == _writePosition인 경우 그 사이에 데이터가 없다는 뜻이므로 이 둘을 0으로 만든다.

 

상황 2: _readPosition < _writePosition 인 경우 사이에 데이터가 있다는 뜻이므로 _readPosition를 0으로 돌려주되 _writePosition 사이에 있는 값까지 함께 가지고 가야한다.

 

OnRead():제대로 다 도착해서 성공적으로 처리했는지 bool 값을 반환함 

3바이트 2개 총 6바이트를 보냈을때 버퍼에 4바이트만와 있다면 앞의 3바이트는 작업하고 뒤의 1바이트는 나머지 2바이트가 올때 까지 기다려야한다. 이때 앞의 3바이트가 도착했는지를 확인하는 용도라고 생각하면된다.

 

OnWrite():현재 보낼 수있는 여유 공간이있는지 지속적으로 Clear()를 할것이기때문에 이게 false로 반환된다면 어디선가 문제가 발생했을것이다.

 

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

namespace ServerCore
{    

    public class ReceiveBuiffer
    {
        ArraySegment<byte> _buffer;
        int _readPosition;
        int _writePosition;

        public ReceiveBuiffer(int bufferSize) 
        {
            _buffer = new ArraySegment<byte>(new byte[bufferSize], 0 ,bufferSize); 
        }

        public int DataSize { get { return _writePosition - _readPosition; } }
        public int FreeSize {  get { return _buffer.Count - _writePosition; } }

        public ArraySegment<byte> ReadSegment //유효데이터 범위의 부분배열
        {
            get { return new ArraySegment<byte>(_buffer.Array, _buffer.Offset + _readPosition, DataSize); }
        }

        public ArraySegment<byte> WriteSegment //받을수있는 데이터 범위의 부분배열
        {
            get { return new ArraySegment<byte>(_buffer.Array, _buffer.Offset + _writePosition, FreeSize); }
        }

         public void Clear() 
        {
            int dataSize = DataSize;

            if(dataSize == 0) //커서가 같은곳에있으니 존재하는 데이터가 없음
            {
                _readPosition = _writePosition = 0;
            }
            else 
            {
                //Array에서 read위치를 dataSize만큼을 복사해서 Array의 시작위치에 올려놓음
                Array.Copy(_buffer.Array, _buffer.Offset + _readPosition, _buffer.Array, _buffer.Offset,dataSize);
                _readPosition = 0;
                _writePosition = dataSize;
            }

        }


        public bool OnRead(int numOfBytes) //제대로 다 도착해서 성공적으로 처리했는지
        {
            if(numOfBytes > DataSize)
                return false;

            _readPosition += numOfBytes;
            return true;
        }

        public bool OnWrite(int numOfBytes) 
        {
            if (numOfBytes > FreeSize)
                return false;

            _writePosition += numOfBytes;
            return true;
        }
    }
}

 

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

[서버 공부]16.PacketSession  (0) 2025.01.16
[서버 공부]15.SendBuffer  (0) 2025.01.15
[서버 공부]12 Session 1,2  (0) 2025.01.12
[서버 공부]11. Listener  (0) 2025.01.12
[서버 공부]10. 소켓 프로그래밍  (0) 2025.01.10