프로그래밍/flutter

소켓통신 첫 4byte 길이 구하기 (비트연산)

소행성왕자 2023. 8. 10. 11:06

List buffer 에는 연결된 소켓에서 데이터를 받아옵니다.

아래 코드의 buffer 는 길이를 얻기위해 첫 4byte 만 추출 한 것입니다.

여기서 buffer는 바이트 배열로, 각각의 원소는 8비트(1byte) 크기의 바이트입니다.

이렇게 바이트 배열로 표현된 데이터를 조합하여 하나의 정수로 만들기 위해 비트 연산을 사용합니다.

코드

List<int> buffer = [0x00, 0x00, 0x07, 0x04]; // 예시 데이터

    int length = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];

    print(buffer[0]);
    print(buffer[1]);
    print(buffer[2]);
    print(buffer[3]);

    int part1 = buffer[0] << 24;  
    int part2 = buffer[1] << 16;  
    int part3 = buffer[2] << 8;   
    int part4 = buffer[3];        


    // 10진수 값을 16진수 문자열로 변환
    print('Part 1: ${part1}');
    print('Part 1: ${part1.toRadixString(16)}');
    print('Part 2: ${part2.toRadixString(16)}');
    print('Part 3: ${part3.toRadixString(16)}');
    print('Part 4: ${part4.toRadixString(16)}');

    print('Length1: ${length.toRadixString(16)}');


    print('Length2: $length');

비트 와 바이트

비트 연산을 이해하기 위해 바이트와 비트에 대한 기본 개념부터 시작해보겠습니다.

컴퓨터에서 데이터는 이진수 형태로 표현됩니다. 

각각의 이진수는 0과 1로 구성되며, 이를 비트(bit)라고 부릅니다. 

8개의 비트가 모이면 1바이트(byte)가 됩니다.

여기서 주어진 코드에서 사용된 비트 시프트(Shift) 연산은 비트들을 왼쪽 또는 오른쪽으로 이동시키는 연산입니다. 

좌측 시프트(<<) 연산은 비트를 왼쪽으로 이동시키며, 새로운 비트가 추가되는 방식으로 동작합니다.

이제 코드를 자세히 살펴보겠습니다:

int length = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];

buffer[0]의 값인 0x00을 24비트 좌측 시프트하면 새로운 비트가 24칸 왼쪽으로 이동됩니다. 
이때, 24비트 만큼의 공간이 생기며, 새로운 값은 0x00000000이 됩니다.

0x00000000은 32비트(4byte) 이진수로 나타낸 값입니다.

buffer[1]의 값인 0x00을 16비트 좌측 시프트하면 새로운 비트가 16칸 왼쪽으로 이동됩니다. 
새로운 값은 0x000000이 됩니다.

buffer[2]의 값인 0x07을 8비트 좌측 시프트하면 새로운 비트가 8칸 왼쪽으로 이동됩니다. 
새로운 값은 0x0700이 됩니다.

buffer[3]의 값인 0x04는 그대로 사용됩니다.

이렇게 시프트 연산을 통해 각 바이트의 값을 적절한 위치로 올려놓고, | 비트 OR 연산을 사용하여 각 비트들을 조합하여 하나의 정수로 만들어냅니다. 

이렇게 하여 바이트 배열을 정수로 해석하게 됩니다.

쉬프트연산 예제

        그럼 0x03 을 24비트 좌측 쉬프트 하면 ?
        0x03 이진수로 표현 00000000 00000000 00000000 00000011

        0x03 << 24
        0x00 00 00 03

        그럼 0x03 을 16비트 좌측 쉬프트 하면 ?
        0x03 << 16
        0x00 03 00 00

        그럼 0x03 을 8비트 좌측 쉬프트 하면 ?
        0x03 << 8
        0x00 00 03 00

        -------------------------------------------------------
        0x00 << 24
        0x00 00 00 00

        0x00 << 16
        0x00 00 00 00

        0x07 << 8
        0x00 00 07 00

        0x04 그대로 사용
        0x00 00 00 04

        ==> |  or 연산하면

        0x00 00 00 00
        0x00 00 00 00
        0x00 00 07 00
        0x00 00 00 04
        -------------
        0x00 00 07 04

        결론 0x00000704
        
        16진수 704
        10진수로 변환하면 1796

 

참고

List<int> buffer = [0x00, 0x00, 0x07, 0x04]; // 예시 데이터

int length = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];

print(buffer[0]);
print(buffer[1]);
print(buffer[2]);
print(buffer[3]);
print('Length: $length');

    

위 코드는 4개의 8비트 바이트로 이루어진 buffer 리스트를 사용하여 정수 값을 생성하는 것입니다. 
각 바이트는 16진수 형식으로 표현되어 있습니다.

buffer 리스트: [0x00, 0x00, 0x07, 0x04]
buffer[0] 값인 0x00을 24비트 좌측 시프트하여 비트열을 생성합니다. 
  이때 24비트를 좌측으로 시프트하면 32비트 정수의 가장 왼쪽 8비트에 0x00이 들어갑니다.

buffer[1] 값인 0x00을 16비트 좌측 시프트하여 비트열을 생성합니다. 
  이때 16비트를 좌측으로 시프트하면 32비트 정수의 가장 왼쪽 16비트에 0x00이 들어갑니다.
  
buffer[2] 값인 0x07을 그대로 사용합니다.
buffer[3] 값인 0x04을 그대로 사용합니다.
위의 4단계를 계산하면 다음과 같은 결과가 나옵니다:

(0x00 << 24) | (0x00 << 16) | (0x07 << 8) | 0x04

이를 계산하면:

0x00000000 | 0x00000000 | 0x00000700 | 0x00000004

그 결과 0x00000704가 됩니다. 이 값은 10진수로 1796입니다. 따라서 length 변수에는 1796가 할당됩니다.