본문 바로가기
Computer Science/TCP&IP 소켓 프로그래밍

3-2. 바이트 정렬 함수(빅 엔디안, 리틀엔디안, htons, ntohs)

by JI NY 2023. 11. 13.

 

01. 바이트 정렬 함수

1) 바이트 정렬(byte ordering)이란?

→ 1바이트 이상의 데이터를 정렬하는 방식

→ 메모리에 데이터를 저장할 때 바이트 순서로, 빅 엔디안 & 리틀 엔디안 방식이 있다.

  • 시스템에서 사용하는 바이트 정렬 방식은 CPU와 운영체제에 따라 다르다.

2) 바이트 정렬 종류

  1. 빅 엔디안(big-endian)
    • 최상위 바이트(MSB, Most Significant Byte)부터 차례로 저장하는 방식
      • ex) 0x12345678이라는 32bit 크기의 데이터가 존재할 경우, 0x12, 0x34, 0x56, 0x78이라고 읽는다.
    • → AMD계열의 CPU에서 이용하는 방식으로, 낮은 주소에 데이터의 가장 높은 바이트부터 정렬하며, 사람이 읽기 좋은 정렬 방식

2. 리틀 엔디안(little-endian)

  • 최하위 바이트(LSB, Least Significant Byte)부터 차례로 저장하는 방식
  • 평소 우리가 숫자를 사용하는 선형 방식과는 반대로 거꾸로 읽어야 함
    • ex) 0x12345678 이라는 32bit 데이터가 존재할 경우, 다음과 같다.Untitled
  1. → 인텔 게열의 CPU에서 이용하는 바이트 오더링 방식으로, 낮은 주소에 데이터의 낮 (LSB, Least Significant Bit)가장 낮은 바이트부터 정렬하는 방식

 

02. 바이트 정렬 방식을 고려해야하는 경우 두 가지 관점

  • 프로토콜 구현
  • 응용 프로그램 데이터
    •  

1) 프로토콜 구현을 위해 필요한 정보

  1. IP 주소의 바이트 정렬 방식에 따른 문제점
    1. 호스트가 보낸 패킷의 IP 헤더에는 IP 주소가 포함되어 있다. 이 패킷을 라우터가 받으면 IP 주소를 찹조해 다음 위치에 있는 라우터에 보낸다. 이때 호스트와 라우터가 IP 주소의 바이트 정렬 방식을 약속하지 않으면, IP 주소 해석이 달라서 라우팅에 문제가 발생할 수 있다.

 

2. 포트 번호의 바이트 정렬 방식에 따른 문제점

  1. 두 호스트가 포트 번호의 바이트 정렬 방식을 약속하지 않으면, 포트 번호 해석이 달라져 데이터가 잘못된 목적지 프로세스에 전달될 수 있다

⇒ 바이트 정렬 방식(호스트 바이트 정렬(host byte ordering)이 통일되어 있지 않아서 이러한 문제들이 발생한다

⇒ 해결법 : IP 주소와 포트번호의 바이트 정렬 방식을 빅 엔디안으로 통일해 사용한다. (리틀엔디안도 괜찮음. 통일만 시키자)

  • 네트워크 용어로서 빅 엔디안: 네트워크 바이트 정렬(network byte ordering)
  • 참고
    • 네트워크 바이트 정렬(Network byte ordering) : 빅 엔디안 방식
    • 호스트 바이트 정렬(host byte ordering) : 시스템이 사용하는 고유한 바이트 ㅈ정렬 방식.

 

2) 응용 프로그램이 주고받는 데이터

  1. 데이터의 바이트 정렬 방식에 따른 문제점
    1. 두 호스트가 주고받는 데이터에 대해 byte ordering(바이트 정렬)을 약속하지 않으면, 데이터 해석 문제가 발생할 수 있다.

해결법 : 대개 네트워크 바이트 정렬(빅 엔디안) 방식을 사용한다.

  • 서버와 클라이언트를 같이 제작하는 경우이거나, 서로 다른 기종간 데이터를 교환하는 경우 상호 약속이 필요하다.

 

03. 바이트 정렬 함수

  • 앞에 H가 붙으면 host
  • 앞에 N이 붙으면 Network
  • 마지막에 붙어있는 s, l은 short이냐 long이냐를 판단하는것.

1) 정렬 함수

  1. 유닉스 호환 바이트 정렬 함수
    1. #include <winsock2.h>
      u_short htons(u_short hostshort); 	// host-to-network-short
      u_long htonl(u_long hostlong); 		  // host-to-network-long
      u_short ntohs(u_short netshort); 	  // network-to-host-short
      u_long ntohl(u_long netlong); 		  // network-to-host-long
      
      return - > 반환된 결과
      ​
       
    2. htons: 호스트 바이트 정렬로 저장된 16비트 값을 입력으로 받아 → 네트워크 바이트 정렬로 변환한 값을 리턴
    3. htonl: 호스트 바이트 정렬로 저장된 32비트 값을 입력으로 받아 → 네트워크 바이트 정렬로 변환한 값을 리턴
    4. ntohs: 네트워크 바이트 정렬로 저장된 16비트 값을 입력으로 받아 → 호스트 바이트 정렬로 변환한 값을 리턴
    5. ntohl: 네트워크 바이트 정렬로 저장된 32비트 값을 입력으로 받아 → 호스트 바이트 정렬로 변환한 값을 리턴
  2. 윈속 확장 바이트 정렬 함수
    1. 			       //소켓 디스크립터, ...       , 반환된 결과 저장할 곳										
      int WSAHtons(SOCKET s, u_short hostshort, u_short *lpnetshort);
      int WSAHtonl(SOCKET s, u_long hostlong, u_long *lpnetlong);
      int WSANtohs(SOCKET s, u_short netshort, u_short *lphostshort);
      int WSANtohl(SOCKET s, u_long netlong, u_long *lphostlong);
      ​
       
    2. 윈속 확장 함수이다.
    3. SOCKET s : 소켓 디스크립터
    4. *lpnetshort : 반환된 결과 저장할 곳

 

2) 바이트 정렬 함수 사용 그림

 

htons(), htonl() 함수는 응용 프로그램소켓 함수에 데이터를 넘겨주기 전에 호출
ntohs(), ntohl() 함수는 소켓 함수가 결과로 리턴한 데이터를 응용프록램이 출력 등의 목적으로 사용하기 전에 호출됨

3) SOCKADDR_IN , SOCKADDR_IN6 구조체의 바이트 정렬 방식

  • TCP/IP에서 사용할 구조체들은 다음과 같은 바이트 정렬 방식을 따른다.

 

04. 실습

  • hton() 함수를 이용해 바이트 정렬을 바꾸고, 다시 ntoh() 함수로 원래 바이트 정렬로 되돌린것이다.

#pragma comment(lib, "ws2_32")
#include <winsock2.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
    WSADATA wsa;
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
        return 1;

    u_short x1 = 0x1234;
    u_long  y1 = 0x12345678;
    u_short x2;
    u_long  y2;

    // 호스트 바이트 -> 네트워크 바이트
    printf("[호스트 바이트 -> 네트워크 바이트]\n");
    printf("0x%x -> 0x%x\n", x1, x2 = htons(x1));
    printf("0x%x -> 0x%x\n", y1, y2 = htonl(y1));

    // 네트워크 바이트 -> 호스트 바이트
    printf("\n[네트워크 바이트 -> 호스트 바이트]\n");
    printf("0x%x -> 0x%x\n", x2, ntohs(x2));
    printf("0x%x -> 0x%x\n", y2, ntohl(y2));

    // 잘못된 사용 예
    printf("\n[잘못된 사용 예]\n");
    printf("0x%x -> 0x%x\n", x1, htonl(x1)); //short인에 long을 썼다.

    WSACleanup();
    return 0;
}

 

 

 

노션에서 정리한걸 티스토리로 옮기려니 색도 다 날라가고 마크다운이 깨지는게 조금 있네요 ㅜ


댓글