🔖IP 주소 변환 함수

IP 주소 변환 함수 설명 전 이해하자!

예) 0x12345678 4바이트 데이터가 있다.
이 데이터가 메모리에 저장될 때 하위 바이트/ 상위 바이트가 저장되는 메모리 주소는 어떻게 될까?

1. 빅 에디안(Big-Endian)
- 하위 바이트가 저장되는 주소가 상위 바이트가 저장되는 주소보다 큰 경우 

0x12 - 1바이트 ➡️ 0x107번지
0x34 - 1바이트 ➡️ 0x108번지
0x56 - 1바이트 ➡️ 0x109번지
0x78 - 1바이트 ➡️ 0x110번지

2. 리틀 엔디안(Little-endian)
- 하위 바이트가 저장되는 주소가 상위 바이트가 저장되는 주소보다 작은 경우
0x12 - 1바이트 ➡️ 0x110번지
0x34 - 1바이트 ➡️ 0x109번지
0x56 - 1바이트 ➡️ 0x108번지
0x78 - 1바이트 ➡️ 0x107번지

 


3.  호스트 바이트 순서 VS 네트워크 바이트 순서
- 바이트 순서는 해당하는 OS 시스템이 내부적으로 데이터를 표현하는 방법

3-1. 호스트 바이트 순서
- 시스템의 CPU에 따라 빅 에디안 방식을 쓸지 리틀 에디안 방식을 쓸지 결정
⚠️ 서로 다른 방식을 사용하는 CPU 간 데이터 교환을 할 경우 문제가 생김 ⚠️

3-2. 네트워크 바이트 순서
- 빅 에디안 방식만을 사용


4. 바이트 순서 변환 함수 종류
htonl: 호스트 바이트 순서 ➡️ 네트워크 바이트 순서 long
htons: 호스트 바이트 순서 ➡️ 네트워크 바이트 순서 short
ntohl: 네트워크 바이트 순서 ➡️ 호스트 바이트 순서 long
ntohs: 네트워크 바이트 순서 ➡️ 호스트 바이트 순서 short

 

문자열 IP ➡️ 네트워크 바이트 순서

 

1. inet_addr

- 문자열 IP 주소 ➡️ 네트워크 바이트 순서

- 성공시 32비트 정수값 / 실패 시 INADDR_NONE 

- 주로 코더들이 쓰는 함수(구조체안에 변환해서 다시 구조체 대입)

serv_addr.sin_addr.s_addr = inet_addr(serv_ip);

 

2. inet_network

- 문자열 IP 주소 ➡️ 호스트 바이트 순서 ➕ ➡️네트워크 바이트 주소

serv_addr.sin_addr.s_addr = htonl(inet_network(serv_ip));

 

3. inet_aton

- 문자열 IP 주소 ➡️ 네트워크 바이트 주소(IN_ADDR 주소에 맞게 변환)

- 성공시 1(true) / 실패 시 0(false)

- 주로 많이 사용(변환시키면서 동시에 대입)

inet_aton(serv_ip, &serv_addr.sin_addr);

 

4. inet_pton

- 특정 형식에 상관없이 변환 🟰 입력 값이 많다는 것을 의미

- 프로토콜 선택

inet_pton(AF_INET, serv_ip, &serv_addr.sin_addr.s_addr);

 


네트워크 바이트 순서 ➡️ 문자열 IP

 

1. inet_ntoa

- INADDR 구조체 주소 ➡️ 문자열 IP 주소

- 성공 시 변환한 문자 주소 값 / 실패 시 -1

char* str_ptr = inet_ntoa(serv_addr.sin_addr)

 

2. inet_ntop

- 프로토콜 선택

- 임의 형식으로 된 주소 ➡️ 문자열 IP 주소

 


전체 소스 코드

#include <cstdio>
#include <netdb.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <memory.h>

int main()
{
	int serv_sock;
    struct sockaddr_in serv_addr;
    char* serv_ip = "127.0.0.1";
	char* serv_port = "8080";

	serv_sock = socket(AF_INET, SOCK_STREAM, 0);

	if (-1 == serv_scok) {
	   exit(1);
	}

	memset(&serv_addr, 0, sizeof(serv_addr)); 

    // 프로토콜 값 입력
	serv_addr.sin_family = AF_INET;
	//문자열 port 값 입력 => 2바이트짜리 숫자로 변경 => 네트워크 바이트로 변경
	serv_addr.sin_port = htons(atoi(serv_port));
  	// 문자열 ip 값 입력 => 바이트 주소로 변환하여 입력
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
		
    /* -----------------------------------------------------------
     그 외의 다양한 ip 값 입력 방법
     -----------------------------------------------------------
    1) inet_addr: 문자열 => 4바이트짜리 네트워크 바이트 주소로 변경
    serv_addr.sin_addr.s_addr = inet_addr(serv_ip);

    2) htonl: 문자열 => 호스트 바이트 주소 => 네트워크 바이트 주소
    serv_addr.sin_addr.s_addr = htonl(inet_network(serv_ip));

    3) inet_aton: 문자열 => 네트워크 바이트 주소
    inet_aton(serv_ip, &serv_addr.sin_addr);

    4) inet_pton: 문자열 => 네트워크 바이트 주소
    inet_pton(AF_INET, serv_ip, &serv_addr.sin_addr.s_addr);
    ----------------------------------------------------------- */

	printf("Network Ordered Addr: %lx\n", serv_addr.sin_addr.s_addr);

	// 네트워크 바이트 주소 => 문자열 IP 주소
	printf("Dotted Decimal IP Addr : %s\n", inet_ntoa(serv_addr.sin_addr));

	return 0;
}

 

참조 : https://swiftymind.tistory.com/57