새소식

C, C++/C TCP, IP

3.3 Network Byte Order (&엔디안)

  • -

Network

네트워크란,

: "물리적으로연결되어 있는" 서로 다른 두 컴퓨터가 데이터를 주고 받는 것이다.

주고 받는 데이터는 Byte 단위로 처리되고, bit 단위로 송수신다.


 

bit & Byte

비트란,

: 컴퓨터가 데이터를 구성하는 최소 단위는 bit(binary digit)라는 0과 1을 저장하는 2진수 한자리 단위이다.

 

바이트란,

: 컴퓨터가 데이터를 처리하는 최소 단위는 Byte 라는 8bit, 즉 1Byte 단위다.


 

Endianness

 

엔디안이란,

: 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상(Byte)이 저장되는 순서(Byte order)

 

리틀 엔디언 & 빅 엔디언 개념 정리 링크 1

리틀 엔디언 & 빅 엔디언 개념 정리 링크 2

 

 

예시1.

Decimal to Binary converter

수 체계        
Decimal  1,991,994
Binary  0000 0000 0001 1110 0110 0101 0011 1010 
Hex  00  1E  65  3A

 

 

예시2.

수 체계        
Decimal  169,283,078
Binary  0000 1010 0001 0111 0000 1110 0000 0110 
Hex  0A 17  0E  06


 

Network Byte Order

 

통신을 하다 보면 통신 패킷이 반대로 나갈 때가 있습니다.

예를 들면 1 2 3 4를 보냈는데 막상 받는 쪽에서 들어온 패킷은 4 3 2 1인 거죠

 

이는 컴퓨터 CPU의 데이터를 저장하는 순서에서 발생하는 오류입니다.

 

메모리에 어떠한 데이터를 저장할 때 큰 쪽을 앞 주소에 두느냐 뒷주소에 두느냐의 차이입니다.

 

저장할 때 상위 바이트. 즉, 큰 쪽을 먼저 저장하는 것을 빅 엔디안(Big Endian),

저장할 때 하위 바이트. 즉, 작은 쪽을 먼저 저장하는 것을 리틀 엔디안(Little Endian)이라고 합니다.

 

네트워크 

  • 네트워크 통신은 데이터를 주고 받을때, Byte 단위 처리한다.
  • 네트워크 통신은 Big-Endian(빅 엔디안) 방식을 사용한다.

Big-Endian(빅 엔디안)

  • 가장 큰 단위(MSB)가 가장 낮은 메모리 주소에 먼저 저장
  • 네트워크와 같이 bit 단위의 연산을 기본으로 한다면, 대부분 Big Endian 방식

Little-Endian(리틀 엔디안)

  • 가장 작은 단위(LSB), 가 가장 낮은 메모리 주소에 먼저 저장
  • 인간이 사용하는 선형 방식과는 반대, 대부분의 인텔, ARM, AMD CPU 계열에서 사용

 

Host Byte Order 문제점

CPU가 데이터를 저장하는 방식이 두가지로 다르다는 의미는,

CPU가 데이터를 해석하는 방식도 두가지로 다르다는 의미다.

 

 

네트워크 바이트 순서(빅 엔디안 시스템)에서 0x12 , 0x34 의 조합으로 만들어지는 값은,

리틀 엔디안 시스템에서 0x34 , 0x12의 조합으로 만들어지는 값과 같다. 

즉, 전송되어온 데이터의 해석 순서가 바뀌어야 동일한 값으로 인식된다.

 

이러한 문제 때문에, 네트워크 전송은 '빅 엔디언' 기준으로 송수신한다.그렇기에 컴퓨터는 수신된 데이가 네트워크 바이트 순서(빅 엔디안) 순서로 정렬되어 있음을 고려하여리틀 엔디언 시스템에서 데이터를 전송하기 앞서 빅 엔디안 방시으로 데이터를 재정렬해야 한다.

 

sockaddr_in 구조체 변수에 데이터를 전달할 때 이외에,
전송되는 데이터는 바이트 순서는 신경쓰지 않아도 된다.

 


 

Endian Conversions (바이트 순서 변환)

n 은 Network을 뜻하며, 바이트 단위, 빅 엔디안 방식을 의미한다.
a 는 Address를 뜻하며, 문자열 단위, 리틀 엔디안 방식을 의미한다.
h 는 Host를 뜻하며, 인텔 그리고 AMD 계열의 CPU를 사용하는 사용자의 PC를 의미한다.
unsigned short htons(unsigned short);  //  host-to-network-unsigned short 바이트 변환
unsigned short ntohs(unsigned short);  //  network-to-host-unsigned short 바이트 변환
unsigned long htonl(unsigned long);    //  host-to-network-unsigned long 바이트 변환
unsigned long ntohl(unsigned long);    //  network-to-host-unsigned long 바이트 변환

// h는 호스트 (host) 바이트 순서
// n은 네트워크 (network) 바이트 순서
// S는 short
// l은 long

// 뒤에 s가 붙는 함수는 s가 2 바이트 short를 의미하므로 PORT번호의 변환에 사용
// 뒤에 l 이 붙는 함수는 l 이 4 바이트를 의미하므로 IP주소의 변환에 사용

Endian Test

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	unsigned short host_port=0x1234;
	unsigned short network_port;
	network_port=htons(host_port);
    
	unsigned long host_addr=0x12345678;
	unsigned long network_addr;
	network_addr=htonl(host_addr);
	
	printf("Host ordered port: %#x \n", host_port);            // 0x1234
	printf("Network ordered port: %#x \n", network_port);      // 0x3412 빅 엔디안
	printf("Host ordered address: %#lx \n", host_addr);        // 0x12345678
	printf("Network ordered address: %#lx \n", network_addr);  // 0x78563412 빅 엔디안
      								   // 16진수 2개는 1바이트다.
    
	return 0;
}

리틀 엔디 안 기준으로 정렬하는 CPU에 서의 실행결과이다.

만약 빅 엔디안 CPU에서 실행을 했다면 변환 후에도 값은 달라지지 않는다.

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.