3.주소체계와 데이터 정렬

#.ip 와 port

ip는 인터넷 프로토콜의 약자로 인터넷 상에서 데이터를 송수신할 목적으로 컴퓨터에게 부여하는 값이다. 반면 port 번호는 컴퓨터에게 부여하는 값이 아닌, 프로그램상에서 생성되는 소켓을 구분하기 위해 소켓에 부여되는 번호를 뜻한다.

 

 

주소의 형태

#.인터넷 주소의 종류 

ip 주소는 IPv4 와 IPv6로 나뉜다. 둘의 차이점은 IP 주소 표현에 사용되는 바이트 크기에 있다. IPv4는 4바이트(32비트) 주소체계이고, IPv6는 16바이트(128비트) 주소체계이다. IPv4 기준의 4바이트 IP 주소는 네트워크 주소와 호스트(컴퓨터) 주소로 나뉘며, 주소의 형태에 따라서 A,B,C,D,E 클래스로 분류가 된다.

 

"IP 주소 = 네트워크 주소 + 호스트 주소"

 

 IPv4 와 IPv6 비교

네트워크 주소란 네트워크의 구분을 위한 IP 주소의 일부를 말한다. 처음부터 4바이트 IP주소 전부를 참조해서 김대리의 컴퓨터로 데이터가 전송되는 것이 아니라, 4바이트 IP주소 중에서 네트워크 주소만을 참조해서 일단 abc.com의 네트워크로 데이터가 전송된다. 해당 네트워크로 데이터가 전송되었다면 해당 네트워크(라우터)는 전송된 데이터의 호스트 주소를 참조하여 김대리의 컴퓨터로 데이터를 전송해준다. 네트워크로 데이터가 전송이 된다는 것은 네트워크를 구성하는 라우터 또는 스위치로 데이터가 전송됨을 뜻한다. 그러면 데이터를 전송 받은 라우터는 데이터에 적혀있는 호스트 주소를 참조하여 호스트에 데이터를 전송해준다.

 

이중에서 203.211.172 와 203.211.217이 네트워크 주소이다. 이를 네트워크 주소 대역이라고 한다.

 

#.라우터&스위치

네트워크를 구성하려면 외부로부터 수신된 데이터를 호스트에 전달하고, 호스트가 전달하는 데이터를 외부로 송신해주는 물리적 장치가 필요하다. 이를 라우터 또는 스위치라한다.

 

 

#.port 번호

컴퓨터에는 NIC(네트워크 인터페이스 카드)이라 불리는 데이터 송수신장치가 하나씩 달려있다. IP는 데이터를 NIC를통해 컴퓨터 내부로 전송하는 데 사용된다. 그러나 컴퓨터 내부로 전송된 데이터를 소켓에 적절히 분배하는 작업은 <운영체제>가 담당한다. 이 때 운영체제는 port 번호를 사용한다. 즉, NIC를 통해서 수신된 데이터 안에는 port 번호가 새겨져 있다. 운영체제는 바로 이 정보를 참조해서 일치하는 port 번호의 소켓에 데이터를 전달하는 것이다.

데이터 분배의 과정

 

port 번호는 하나의 운영체제 내에서 <소켓을 구분하는 목적>으로 사용되기 때문에 하나의 운영체제 내에서 동일한 port 번호를 둘이상 소켓에 할당할 수 없다. 그리고 port 번호는 16비트로 표현된다. 따라서 할당할 수 있는 범위는 0에서 65535이하 이다.

(tcp 소켓과 udp 소켓은 port 번호를 공유하지 않기 때문에 중복되어도 상관없다.)

 

 

#.IPv4 기반의 주소표현을 위한 구조체

이 구조체는 bind 함수에 주소 정보를 전달하는 용도로 사용된다.

 

struct sockaddr_in{

    sin_family_t sin_family;   // (주소체계)

    unist16_t sin_port;         // 포트 번호. 16비트 tcp/udp port 번호

    struct in_addr sin_addr; // IP주소를 나타내는 32비트 정수 타입 구조체

    char sin_zero[8];         // sockaddr과 같은 크기를 유지하기 위해 필요한 패딩(padding) 공간. 항상 0.

}

 

 

*설명

sin_family : 주소체계 ( AF_INET (IPv4전용) / AF_INET6 (IPv6전용) / AF_LOCAL (로컬 전용) ) 

sin_port : 16비트 포트정보 (네트워크 바이트 오더 적용 = Big Endian) 2bytes 이다. 즉, 포트번호는 0~65535 의 범위를 갖는 숫자 값이다. 

sin_addr : 32비트 IP정보 (네트워크 바이트 오더 적용 = Big Endian)

sin_zero : 사용되지 않는 필드 

 

struct in_addr {

  u_long s_addr;   // 32비트 IPv4 주소를 저장 할 구조체, network byte order 

};


#.빅-엔디안(big-endian)방식과 리틀-엔디안(little-endian)방식

 

*빅엔디안 : 상위 바이트의 값이 메모리상에 먼저 표시되는 방법

   

*리틀 엔디안 : 하위 바이트의 값이 메모리상에 먼저 표시되는 방법

   

예를 들어 0x12345678 이란 데이터를 메모리에 쓰면  빅엔디안은 아래와 같이 메모리에 표시된다. 

0x12

0x34

0x56

0x78

리틀엔디안은 아래와 같이 메모리에 표시된다.   

0x78

0x56

0x34

0x12

   

이것은 CPU에 따라 달라진다.

 

*호스트 바이트 순서   

메모리에 표현되는 것 즉, 어떠한 순서로 데이터들이 메모리에 쓰여지는 것을 말함.

   

문제는 CPU에  따라 호스트 바이트 순서가 달라서  서로 다른 CPU 사용하는 컴퓨터들 통신할때 문제가 발생한다. 문제점 때문에  네트워크 바이트 순서 생겨났다. 네트워크 바이트 순서는 빅엔디안  방식이다. 리틀엔디안 방식을 사용하는 컴퓨터는 데이터를 보내기 전에 빅엔디안 방식으로 데이터를 바꿔야 하고 받을 때도 전송되는 데이터들을 역순으로 받아 조합해야 한다.

또한 sockaddr_in 구조체 안에 존재하는 모든 값들은 네트워크 바이트 순서로 채워져야 한다.

 

#.주소 변환 관련 API

inet_addr : (ipv4) 문자열의 인터넷주소를 32bit 이진 데이터 주소로 변환

inet_ntoa : (ipv4) 32bit 이진 데이터 주소에서 문자열의 인터넷주소로 변환

inet_pton : (ipv6, ipv4) 문자열 인터넷주소를 128bit 이진 데이터 주소로 변환

inet_ntop : (ipv6, ipv4) 128bit 이진 데이터 주소에서 문자열 인터넷주소로 변환

 

 

#.엔디언 컨버터 예제

결과

 

 

#.문자열로 표현된 ip 주소를 32비트 정수형으로 변환해주는 함수 예제

결과

network ordered integer addr : 0x4e7cd47f

 

 

#.inet_aton()함수 예제

결과

network ordered integer addr : 0x4f7ce87f

 

 

#.inet_ntoa 함수 예제

 

 

 

 

 

참고: 윤성우 열혈 tcp/ip 소켓프로그래밍