bdfgdfg

[C# 서버] ArraySegment - 버퍼 부분 참조 본문

게임프로그래밍/C# 서버

[C# 서버] ArraySegment - 버퍼 부분 참조

marmelo12 2022. 4. 29. 21:54
반응형

C++에서는 포인터를 쓰면 간단하게 해결할 문제이지만 C#은 버퍼의 인덱스부터 ~ 어느 인덱스까지를 사용하는건 어렵다.

 

이때 사용할 수 있는게 ArraySegment.

 

네트워크 송수신에서 데이터를 주고 받기 위해 정의된 패킷타입이 다음과 같다고 보자.

// [패킷 프로토콜][패킷 길이][데이터 필드]
// [2byte(Protocol)][2byte(Length)][N-byte(Data Field)]

해당 데이터를 해석하기 위한 별도의 클래스나 툴이없다면 직접 부분참조해서 읽어와야 한다.

class Program
{
    static void Main(string[] args)
    {
        ArraySegment<byte> packetBuffer = new ArraySegment<byte>(new byte[1024], 0, 1024);
        int writePos = 0;
        int readPos  = 0;

        const ushort gameStartProtocol = 1234;
        
        int[] data = new int[3] { 10, 20, 30 }; // Data Field
        
        // 직렬화 

        // 프로토콜
        Array.Copy(BitConverter.GetBytes(gameStartProtocol), 0, packetBuffer.Array, packetBuffer.Offset + writePos, sizeof(ushort));
        writePos += sizeof(ushort);
        // 패킷 길이. (헤더 + 데이터 필드)
        Array.Copy(BitConverter.GetBytes(4 + data.Length * sizeof(int)), 0, packetBuffer.Array, packetBuffer.Offset + writePos, sizeof(ushort));
        writePos += sizeof(ushort);
        // 데이터 필드
        Array.Copy(BitConverter.GetBytes(data[0]), 0, packetBuffer.Array, packetBuffer.Offset + writePos, sizeof(int));
        writePos += sizeof(int);
        Array.Copy(BitConverter.GetBytes(data[1]), 0, packetBuffer.Array, packetBuffer.Offset + writePos, sizeof(int));
        writePos += sizeof(int);
        Array.Copy(BitConverter.GetBytes(data[2]), 0, packetBuffer.Array, packetBuffer.Offset + writePos, sizeof(int));
        writePos += sizeof(int);

        //역직렬화.

        //프로토콜
        ushort protocolID = BitConverter.ToUInt16(packetBuffer.Array,readPos);
        readPos += sizeof(ushort);
        ushort packetLen = BitConverter.ToUInt16(packetBuffer.Array, readPos);
        readPos += sizeof(ushort);

        int data1 = BitConverter.ToInt32(packetBuffer.Array, readPos);
        readPos += sizeof(int);
        int data2 = BitConverter.ToInt32(packetBuffer.Array, readPos);
        readPos += sizeof(int);
        int data3 = BitConverter.ToInt32(packetBuffer.Array, readPos);
        readPos += sizeof(int);

        Console.WriteLine($"프로토콜 : {protocolID} 패킷 길이 : {packetLen}");
        Console.WriteLine($"데이터 : {data1},{data2},{data3}");

    }
}

간단하게 ArraySegment를 이용해보았다. 사실은 ArraySegment가 아니더라도 단순히 byte배열을 이용해도 위의 코드는 처리가 가능하다.

단 ArraySegment의 가장 강력한점은 밑과 같다.

ArraySegment<byte> array = new ArraySegment<byte>(packetBuffer.Array, 0, sizeof(ushort));

packetBuffer의 해당 인덱스부터 시작해 할당한 길이만큼의 버퍼를 가져올 수 있는 것.(원본의 버퍼)

실제 2바이트만큼 할당하였고, Count가 2인것을 알 수 있음.

또한 2번째인자를 0으로 준것은 packetBuffer의 0번째 인덱스부터 길이 2만큼의 부분 버퍼를 가져온 것인데.

이 시작 인덱스를 달리하여 원하는 길이만큼의 버퍼도 당연히 얻어올 수 있다.

ArraySegment<byte> array = new ArraySegment<byte>(packetBuffer.Array, 2, sizeof(ushort));

Offset이 2인모습.

 

즉. packetBuffer의 인덱스 2부터 3까지는 패킷의 길이를 나타내는데, 위를 활용하면.

ArraySegment<byte> array = new ArraySegment<byte>(packetBuffer.Array, packetBuffer.Offset + 2, sizeof(ushort));
Console.WriteLine(BitConverter.ToUInt16(array.Array,array.Offset));

위와 같이 적용가능하다.

반응형
Comments