바이트 순서 관련 함수
네트워크 프로그래밍을 위해 추가로 신경 써야 하는 것이 바로 데이터의 바이트 순서이다.
바이트 순서는 리틀 엔디언과 빅 엔디언의 두 가지가 있다. Intel 의 경우 리틀 엔디언을 사용하고 모토로라 등은 빅 엔디언을 사용하는데 이때 각각의 엔디언에 맞게 전송해주어야 한다.
종류 | 0x12345678의 표현 |
리틀 엔디언(Little Endian) | 78 56 34 12 |
빅 엔디언(Big Endian) | 12 34 56 78 |
대부분의 호스트 시스템은 리틀 엔디언을 사용하고 대부분의 네트워크 장비는 빅 엔디언 방식을 사용하기 때문에 네트워크 프로그래밍을 할 때에는 이를 맞춰 변환 해주어야 한다.
이에 C 언어는 효율적으로 바이트 순서를 변환할 수 있다록 지원한다.
이번 포스트에서는 그 함수들을 알아보자.
header : #include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong)
> 4바이트 값의 호스트 바이트 순서를 네트워크 바이트 순서로 변환한다.
uint32_t htons(uint32_t hostshort)
> 2바이트 값의 호스트 바이트 순서를 네트워크 바이트 순서로 변환한다.
uint32_t ntohl(uint32_t netlong)
> 4바이트 값의 네트워크 바이트 순서를 호스트 바이트 순서로 변환한다.
uint32_t ntohs(uint32_t netshort)
> 2바이트 값의 네트워크 바이트 순서를 호스트 바이트 순서로 변환한다.
네트워크 바이트 순서와 호스트 바이트 순서 비교 예제
#include <stdio.h> #include <arpa/inet.h> void print2hex(const char *msg, void *p, size_t len); int main(void) { int a = 0x12345678; int b = htonl(0x12345678); int c = htonl(b); print2hex("a", &a, sizeof(a)); print2hex("b", &b, sizeof(b)); print2hex("c", &c, sizeof(c)); } void print2hex(const char *msg, void *p, size_t len){ size_t i; printf("%s :\n",msg); for(i=0;i<len;i++){ printf("[%p]%x ",((char*)p+i), *((char*)p+i)); } printf("\n"); }
출력
a : [0x7ffcaa5c21e4]78 [0x7ffcaa5c21e5]56 [0x7ffcaa5c21e6]34 [0x7ffcaa5c21e7]12 b : [0x7ffcaa5c21e8]12 [0x7ffcaa5c21e9]34 [0x7ffcaa5c21ea]56 [0x7ffcaa5c21eb]78 c : [0x7ffcaa5c21ec]78 [0x7ffcaa5c21ed]56 [0x7ffcaa5c21ee]34 [0x7ffcaa5c21ef]12
위 출력에서 a는 호스트에서 저장될 때 리틀 엔디언으로 저장되는 것을 보여준다.
b와 같은 경우는 htonl()함수를 동해 리틀 엔디언을 빅 엔디언으로 변환 한 것을 보여준다.
c와 같은 경우는 htonl()함수를 다시 사용해 빅 엔디언을 리틀 엔디언으로 변환 한 것 이다.
위와 같이 htonl()과 ntohl()을 크게 구분하지 않아도 되지만,
프로그래밍 함에 있어서 버그를 발생 시키지 않도록 구분해서 사용하는 것이 좋다.
네트워크 주소와 관련된 함수
header : #include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp)
> 일반적으로 표기하는 IP 주소 형태(0.0.0.0)를 4 Byte의 네트워크 바이트 순서로 변환하는 함수
char *inet_ntoa(strcut in_addr in)
> 4 Byte의 네트워크 바이트 순서를 일반적으로 표기하는 IP 주소 형태(0.0.0.0)로 변환하는 함수
inet_addr 및 inet_ntoa 사용 예제
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> void print2hex(void *p, size_t len); int main(void) { struct in_addr addr; addr.s_addr = inet_addr("127.0.0.1"); printf("inet_addr : %08x\n", addr.s_addr); print2hex(&addr.s_addr, sizeof(addr.s_addr)); printf("inet_ntoa : %s\n", inet_ntoa(addr)); return 0; } void print2hex(void *p, size_t len){ size_t i; for(i=0;i<len;i++){ printf("[%p]%x ",((char*)p+i),*((char *)p+i)); } printf("\n"); }
출력
inet_addr : 0100007f [0x7ffe0f730c30]7f [0x7ffe0f730c31]0 [0x7ffe0f730c32]0 [0x7ffe0f730c33]1 inet_ntoa : 127.0.0.1 Press <RETURN> to close this window...