본문 바로가기
열심히 살기/Network

소켓 프로그래밍 - 바이트 순서(호스트, 네트워크)

by yeni03o_o 2020. 12. 12.

Little Endian과 Big Endian

※ Little Endian

   * 하위 바이트 값부터 메모리에 적재

   * 0x1234 5678 → 0x7856 3412

※ Big Endian

   * 상위 바이트 값부터 메모리에 적재

   * 0x1234 5678 → 0x1234 5678

 

 

호스트 바이트 순서

: CPU별 데이터 저장방식

Little Endian Big Endian
intel x86 IBM
AMD RISC 기반 CPU(ARM, Motorola)

 

 

네트워크 바이트 순서

: 통일된 데이터 송수신 기준. Big Endian 방식만 사용

 

 

바이트 변환 함수

unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
h 호스트 바이트 순서
n 네트워크 바이트 순서
s short 자료형(2byte). 일반적으로 포트 변환에 사용
l long 자료형(4byte). 일반적으로 IP 변환에 사용

 

 

Endian Converter

//endian_conv.c

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

int main(int argc, char *argv[])
{
    unsigned short host_port=0x1234;
    unsigned short net_port;
    unsigned long host_addr=0x12345678;
    unsigned long net_addr;
    
    net_port=htons(host_port);	# 네트워크바이트 순서(Big Endian)로 변환
    net_addr=htonl(host_addr);	# 네트워크바이트 순서(Big Endian)로 변환
    
    printf("Host ordered port: %#x \n", host_port);
    printf("Host ordered port = %#x => Network ordered port: %#x \n", host_port, net_port);
    printf("Host ordered address: %#lx \n", host_addr);
    printf("Host ordered address: %#lx => Network ordered address: %#lx \n", host_addr, net_addr);
    
    return 0;
}

 

코드(Endian_conv.c) 실행 결과

Endian_conv.c 실행 결과

 


 

주소 변환 API

 * inet_addr(): IP주소(Dotte-Decimal Notation)를 네트워크 바이트 순서(Big Endian 32bit)의 바이너리 데이터로 리턴.

                  잘못된 값 입력 시 INADDR_NONE(-1) 리턴

#include <arpa/inet.h>

// 성공 시 Big Endian으로 변환된 32비트 정수 값, 실패 시 INADDR_NONE 반환
in_addr_t inet_addr(const char *string);

 * inet_network(): 호스트 바이트 순서의 바이너리 데이터 리턴

 * inet_aton(): inet_addr() 개선. IP주소를 in_addr 구조체로 변환

#include <arpa.inet.h>

//성공 시 1(true), 실패 시 0(false) 반환
int inet_aton(const char *string, struct in_addr *addr);
*string: 변환할 IP주소 주소값
*addr: 변환된 정보를 저장할 in_addr 구조체 변수의 주소값

 * inet_nota(): 네트워크 바이트 순서의 바이너리 주소를 IP주소로 변경

#include <arpa/inet.h>

//성공 시 변환된 문자열 주소 값, 실패 시 -1 반환
char *inet)ntoa(struct in_addr adr);

 

 

IP주소(10진수 표현방식) → 네트워크 바이트 순서 변환

// inet_addr.c

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

int main(int argc, char *argv[])
{

    char *addr1="127.212.124.78";
    
    //in_addr_t net_addr(const char *string);	→ 	성공 시 Big Endian으로 변환된 32비트 정수 값, 실패 시 INADDR_NONE 반환
    unsigned long conv_addr=inet_addr(addr1);			//Dotte-Decimal Notation -> Big Endian 32비트 값
    
    if(conv_addr==INADDR_NONE)
    	printf("Error occured! \n");      
    else
    	printf("주소문자열 %s ==> Network ordered integer addr; %#lx \n", addr1, conv_addr);
        
    char *addr2="127.212.124.254";
    
    unsigned long conv_addr2 = inet_addr(addr2);
    
    if(conv_addr2=INADDR_NONE)
    	printf("Error occureded \n");
    else
    	printf("주소문자열 %s ==> Network ordered integer addr: %#lx \n\n", addr2, conv_addr2);
        
    return 0;
}

 

코드(inet_addr.c) 실행 결과

- 10진수로 된 IP주소(문자열)을 32비트 정수형으로 변환하여 출력

inet_addr.c 실행 결과

 

 

inet_aton() 및 inet_ntoa()

//aton_ntoa.c

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

void error_handling(char *message);

int main(int argc, char *argv[])
{
    /* aton() */
    char *addr="127.232.124.79";		//주소 문자열
    struct sockaddr_in addr_inet;		//주소 셋팅 구조체
    
    //주소 문자열을 Big Endian 32비트 값으로 변환한 값을 sockaddr_in구조체의 sin_addr에 대입 후 출력
    if(!inet_aton(addr, &addr_inet.sin_addr))
    	error_handling("Conversion error");
    else
    	printf("[aton function] Network Address %s => Network ordered integer addr: %#x \n", addr, addr_inet.sin_addr.s_addr);
    
    
    /* ntoa() */
    struct sockaddr_in addr1, addr2;
    char *str_ptr;
    char str_arr[20];
    
    addr1.sin_addr.s_addr=htonl(0x1020304);
    addr2.sin_addr.s_addr=htonl(0x1010101);
    
    str_ptr=inet_ntoa(addr1.sin_addr)
    //printf("str_ptr %s \n", str_ptr);
    strcpy(str_arr, str_ptr);
    printf("[ntoa function] addr1 = %lx Dotted-Decimal notation1: %s \n", addr1.sin_addr.s_addr, str_ptr);
    
    inet_ntoa(addr2.sin_addr);
    //printf("str_ptr %s \n", str_ptr);
    printf("Dotted-Decimal notation2: %s \n", str_ptr);		//리턴된 포인터가 str_ptr로 유지되므로 1.1.1.1 출력
    printf("[ntoa function] addr2 = %lx Dotted-Decimal notation3: %s \n", addr2.sin_addr.s_addr, str_arr); 
    
    return 0;
}

void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}

 

코드(aton_ntoa.c) 실행 결과

aton_ntoa.c 실행 결과 

 

공부하면서 학습 목적으로 작성한 포스팅이므로 내용이 완전하지 않습니다ㅠ 
계속해서 학습 후 지식이 좀 더 쌓이면 수시로 수정해나갈 예정입니다! 
틀린 내용은 둥글게 댓글 달아주시면 빠른 확인 후 수정하겠습니다. :)


코드 출처

윤성우 저 '윤성우의 열혈 TCP/IP 소켓 프로그래밍'

 

참고

* 윤성우 저 '윤성우의 열혈 TCP/IP 소켓 프로그래밍'

* swiftymind.tistory.com/57

* qteveryday.tistory.com/47

 

댓글