바이트 정렬 방식에 대해서 알아보자잉

 

1. 바이트 정렬

 - 바이트 정렬이란 메모리에 데이터를 저장할 때 바이트 순서를 나타내는 것으로, 빅엔디안, 리틀엔디안 알쥬?

    빅엔디안 : 최상위 바이트부터 차례로 저장되는 방식

    리틀엔디안 : 최하위 바이트부터 차례로 저장되는 방식

  그래서, 바이트 정렬 방식이 틀릴 경우 잘못된 데이터가 전달될 가능성이 있다, 이러한 모호함을 없애기 위해서 ip주소와 포트번호의 바이트 정렬 방식은 빅엔디안으로 통일되어있다. 그런데, 인텔 프로세스에서는 바이트 정렬을 리틀엔디안 방식으로 하고있어서 ip주소와 포트번호를 정렬하는 방식과 맞지 않다, 따라서 빅엔디안을 네트워크 바이트 정렬이라고하고 시스템이 사용하는 정렬 방식을 호스트 바이트 정렬이라 한다.



 

2, 바이트 정렬 함수

 - 그래서 바이트 정렬 함수를 보면

 - htonl() - 호스트 -> 네트워크 long형 (32비트)

 - htons() - 호스트 -> 네트워크 short형 (16비트)

 - ntohl() - 네트워크 -> 호스트 long형 (32비트)

 - ntohs() - 네트워크 -> 호스트 short형 (16비트)

 - 함수 이름만 봐도 사이즈 나오지유? h to nl ㅇㅋ?

 

예제한번보자

 

 

3. 예제

 

#include <Winsock2.h>

#include <stdio.h>

 

int main()

{

   short x = 0x1234;

   long y = 0x12345678;

  

   short x2;

   long y2;

 

   printf("호스트 바이트 -> 네트워크 바이트\n");

   printf("0x%x -> 0x%x\n", x, x2 = htons(x));

   printf("0x%x -> 0x%x\n", y, y2 = htonl(y));

 

   printf("네트워크 바이트 -> 호스트 바이트\n");

   printf("0x%x -> 0x%x\n", x2, x2 = ntohs(x));

   printf("0x%x -> 0x%x\n", y2, y2 = ntohl(y));

 

   return 0;

}

 

결과

호스트 바이트 -> 네트워크 바이트

0x1234 -> 0x3412

0x12345678 -> 0x78563412

 

네트워크 바이트 -> 호스트 바이트

0x1234 -> 0x1234

0x12345678 -> 0x12345678

 


그러니까,

빅엔디안 : 0x12 0x34 0x56 0x78

리틀엔디안 : 0x78 0x56 0x34 0x12

이런식의 저장형태

 

4. 소켓 구조체

 - 소켓 구조 구조체는 네트워크 프로그램에서 필요로하는 주소정보를 담고있는 구조체로 다양한 소켓 함수 인자로 사용한다. 여러 소켓 주소 구조체 중 가장 기본이 되는 것은 SOCKADDR이다. 또한 각 애플리케이션이 사용할 프로토콜의 종류에 맞는 소켓 구조체를 사용하는데, 어쨋든 TCP/IP로 할꺼니까 요고만 함 보자

 

 - 구조

   : struct sockaddr_in {

       short                sin_family;

       unsigned short  sin_port;

       struct in_addr    sin_addr;

       char                 sin_zero[8];      // 사용되지 않음

     };

   : sin_family - 주소 패밀리 걍 무조건 IN_ADDR

   : sin_port - 포트번호

   : sin_addr - 아이피 번호

                  - 얘는 IN_ADDR 타입의 또다른 구조체이기 때문에, IN_ADDR 구조체를 이용

                     해서 아이피를 넣어줘야해

 

 

5. IP 주소변환함수

 - 윈도우 애플리케이션에는 IP주소를 입력받기 위해 명령행 인자를 사용하거나 에디트 컨트롤을 사용하는 경우가 있다, 이때 애플리케이션은 IP주소를 문자열 형태로 전달받게되는데 요고를가지고 32비트 숫자로 전환해야한다. 따라서 윈속에서는 IP주소 변환을 통해 아래와같은 함수를 지원한다.

  : inet_addr() - 문자열형태 -> 32비트 숫자

  : inet_ntoa() - 32비트 숫자 -> 문자열형태

 


 

6. 예제

#include <Winsock2.h>

#include <stdio.h>

 

int main()

{

    // 윈속 초기화

   WSADATA wsa;

   if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)

        return -1;

 

   char *ipAddr = "111.110.109.108";

   long a = inet_addr(ipAddr);               // 문자열 형태로 변경

   printf("IP주소 : %s\n", ipAddr);

   printf("네트워크 바이트 정렬 : %x\n", a);

   printf("네트워크 바이트 정렬 : %x\n\n", inet_addr(ipAddr));

 

   IN_ADDR temp, m_temp;

   temp.S_un.S_addr = inet_addr(ipAddr);     // IN_ADDR 형태로 ip주소 저장

   m_temp.s_addr = inet_addr(ipAddr);

   printf("IP 주소 = %s\n", inet_ntoa(temp);

   printf("IP 주소 = %s\n", inet_ntoa(m_temp);

 

   BYTE b_val = temp.S_un.S_un_b.s_b1;    // temp에 저장된 주소 중 b1만 즉, 첫번째 자리만

 

   printf("IP 주소 = %d\n", b_val);

 

   // 윈속 종료

   WSACleanup();

   return 0;

}

 

결과

IP주소 = 111.110.109.108

네트워크 바이트 정렬 = 6c6d6e6f

네트워크 바이트 정렬 = 6c6d6e6f

 

IP주소 = 111.110.109.108

IP주소 = 111.110.109.108

 

IP주소 = 111

 

IN_ADDR 구조체


 - 위 그림에서 보듯 동일한 메모리 영역(temp)을 각각 8비트(S_un_b), 16비트(S_un_w), 32비트(S_addr) 단위로 접근할 수 있게 만든 S_un 구조체

 - 구조체 안에 #define s_addr S_un.S_addr 이라는 정의문이 존재하기 때문에, m_temp.s_addr이라는 접근이 가능 결국은 m_temp.S_un.S_addr이라는 문장과 같은 효과


'Web, Network Programming > Socket' 카테고리의 다른 글

TCP 서버/클라이언트  (0) 2014.06.16
도메인 네임 서버  (0) 2014.06.16
Socket 생성  (0) 2014.05.29
WS2_32.DLL  (0) 2014.05.29
initSocketLayer  (0) 2014.05.29
Posted by 긍정왕오킹