. 11.3 글로벌 IP 인터넷
본문 바로가기
프로그래밍 공부/CSPP

11.3 글로벌 IP 인터넷

by 불냥이_ 2021. 1. 22.

그림 1. 인터켓 클라이언트-서버의 기본적인 하드웨어/소프트웨어의 구조

 

 각 인터넷 호스트는 TCP/IP;Transmission Control Protocol / Internet Protocol 라는 프로토콜을 구현한 소프트웨어를 실행하며, 현대 인터넷의 기반이 된다.

 

 인터넷 클라이언트와 서버는 소켓 인터페이스와 Unix I/O 함수들의 혼합을 사용해서 통신한다. 소켓 함수들은 일반적으로 시스템 콜들로 구현되는데, 이 시스템 콜은 커널에서 트랩을 발생시키며, TCP/IP에서 다양한 커널 모드 함수들을 호출한다.

 

 사실 OSI모형에서 TCP는 UDP와 같이 4단계-전송계층, IP는 3단계-네트워크 계층에 속한 별개의 프로토콜이나, 일반적으로 TCP/IP를 묶어서 다루고 UDP는 다루지 않을 것이다. 

 

 

 

IP 주소

 본격적인 IP주소에 들어가기에 앞서, 소켓을 배우다보면 네트워크 바이트 순서, 호스트 바이트 순서가 나와있다. 도대체 네트워크 순서는 뭐고, 호스트 순서는 무엇인가.

 

 (m.blog.naver.com/ifkiller/70081338547 에서 발췌 )

 이것은 메모리 상에 값을 표시할 때 CPU에 따라, 상위 바이트 값을 먼저 표시하게 하는 빅 엔디안 방식과 하위 바이트 값을 표시하는 리틀 엔디안 방식이 있기 때문이다. 예를 들어 0x12345678 이란 데이터를 메모리에 쓴다면,

 

1) 빅 엔디안 방식

2) 스몰 엔디안 방식

 

위와 같이 표시될 것이다. 이렇게 CPU에 따라 데이터들이 메모리에 쓰이는 순서가 달라지는데 이것을 호스트 바이트 순서라고 한다.

 

 문제는 다른 바이트 순서를 가지고 있는 CPU간에 통신할 때 발생한다. 서로 메모리에 쓰는 순서가 다르기 때문에 데이터가 오독되어질 가능성이 생겨버리는 것이다.

 

 이 때문에 CPU에 관계없이 네트워크를 통해 데이터를 전송할 때는 통일된 방식을 사용하기로 약속을 했고, 이 약속을 네트워크 바이트 순서라고 한다. 네트워크 바이트 순서는 빅 엔디안 방식만 사용하기로 되어있다.

 

 그렇기에 리틀 엔디안 방식의 컴퓨터라도 네트워크를 통해 데이터를 보내고 싶다면 빅 엔디안 방식으로 바꿔서 전송해야할 의무가 생기며, 네트워크를 통해 데이터를 받아도 스몰 엔디안 방식으로 바꾼 후에 읽어들여야한다. 

 

 이때문에 다음과 같은 함수가 존재한다. 

#include <arpa/inet.h>

// 비부호 32비트 정수를 호스트 바이트 순서에서 네트워크 바이트 순서로 변환 (host to network. long)
uint32_t htonl(uint32_t hostlong);
// 비부호 16비트 정수를 호스트 바이트 순서에서 네트워크 바이트 순서로 변환 (host to network. short)
uint16_t htons(uint16_t hostshort);
		Returns: value in network byte order

// 비부호 32비트 정수를 네트워크 바이트 순서에서 호스트 바이트 순서로 변환 (host to network. long)
uint32_t ntohl(uint32_t netlong);
// 비부호 16비트 정수를 네트워크 바이트 순서에서 호스트 바이트 순서로 변환 (host to network. short)
uint16_t ntohs(unit16_t netshort);
		Returns: value in host byte order

 

 IP주소는 흔히 우리가 알고 있는 점으로 구분되어 있는 4군의 3자리 숫자로 표현된다. ( dotted-decimal 방식;presentation 이라고 표현한다. )

예) 128.2.194.242 (이 주소는 메모리 상으로는 0x8002c2f2(network라고도 표현한다.)

 

 그래서 이 network와 presentation도 서로 바꿔주는 함수도 필요하다.

#include <arpa/inet.h>
// presentation을 network로 바꾼다. 
int inet_pton(AF_INET, const char *src, void *dst);
		Returns: 1 if OK, 0 if src is invalid dotted decimal, −1 on error
        
// network를 presentation으로 바꾼다.
const char *inet_ntop(AF_INET, const void *src, char *dst,
socklen_t size);
		Returns: pointer to a dotted-decimal string if OK, NULL on error

 inet_pton함수는 점-십진수;dotted-decimal 스트링 (src)를 네트워크 바이트 순서를 갖는 이진 IP주소(dst)로 변한한다. 

 

위 함수의 예제는 다음과 같다.

IPv6 프로그래밍 (joinc.co.kr)에서 발췌

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
    ulong ipv4_addr;
    char  ipv6_addr[16];

    char addr4_str[20];
    char addr6_str[40];

    struct in_addr  st_addr4;
    struct in6_addr st_addr6;

    // IPv4 인터넷 주소 변환 예제 
    inet_pton(AF_INET, "192.168.0.224", (void *)&ipv4_addr);
    printf("presentation -> network : %lu\n", ipv4_addr);

    st_addr4.s_addr = ipv4_addr;
    inet_ntop(AF_INET, (void *)&st_addr4,addr4_str,sizeof(addr4_str));
    printf("network -> presentation : %s\n\n", addr4_str);

}

 위는 192.168.0.224 를 정수형 ( 긴 정수형;ulong 을 선언한 것에 유의하자.) 으로 바꾸고 (presentation -> network),

다시 그 정수형을 우리가 아는 IP 번호로 바꾸었다. (network -> presentation)

 

 AF_INET은 주소체계를 의미하며, 이 자리에는 프로토콜 체계인 PF_INET 도 들어갈 수 있음에 유의하자.

 

 

 

 

 

 

 

 

 

 

댓글