3-1. 소켓에 할당되는 IP주소와 PORT 번호
1) 인터넷 주소(Internet Address)
- 인터넷 주소란?
- 인터넷 상에서 컴퓨터를 구분하는 목적으로 사용되는 주소
- 4바이트 주소체계인 IPv4와 16바이트 주소체계인 IPv6가 존재
- 소켓을 생성할 때 기본적인 프로토콜을 지정해야 한다.
- 네트워크 주소와 호스트 주소로 나뉜다. 네트워크 주소를 이용해서 네트워크를 찾고, 호스트 주소를 이용해서 호스트를 구분
2) 클래스 별 네트워크 주소와 호스트 주소의 경계(SKIP)
때문에 첫 번째 바이트 정보만 참조해도 IP 주소와 클래스 구분이 가능하며, 이로 인해서 네트워크 주소와 호스트 주소의 경계 구분이 가능
3) 소켓 구분에 활용되는 PORT번호
- PORT번호
- PORT번호는 16비트로 표현, 따라서 그 값은 0 이상 65535 이하
- 0 ~ 1023은 잘 알려진 PORT(Well-known PORT)라 해서 이미 용도가 결정되어 있다.
- PORT번호와 소켓이 1 대 1 매핑이 된다고 일단 생각하기
3-2 주소 정보의 표현
1) IPv4 기반의 주소표현을 위한 구조체
- IP주소와 PORT 번호는 구조체 sockaddr_in의 변수에 담아서 표현한다.
struct sockaddr_in
{
sa_family_t sin_family; // 주소체계(버전에 대한 정보)
uint16_t sin_port; // 포트 번호
struct in_addr sin_addr; // 32비트 IP 주소
char sin_zero[8]; // 사용되지 않음
};
struct in_addr
{
in_addr_t s_addr;
}; // 32비트 IPv4 인터넷 주소
IP 주소는 원래 32bit 짜리 정수인데 이를 binary로 바꿔서 1 바이트씩 귾어서 표한 한 것이 우리가 평소에 알고 있는 165.246.32.46같은 형식이다.
2) 구조체 sockaddr_in의 멤버에 대한 분석
- 멤버 sin_family : 주소체계 정보 저장
- 멤버 sin_port : 16비트 port번호 저장 / 네트워크 바이트 순서로 저장
- 멤버 sin_addr : 32비트 IP주소정보 저장 / 네트워크 바이트 순서로 저장
멤버 sin_addr의 구조체 자료형 in_addr 사실상 32비트 정수자료형 - 멤버 sin_zero : 특별한 의미를 지니지 않는 멤버 / 반드시 0으로 채워야 함
3) 구조체 sockaddr_in의 활용의 예
- 구조체 sockaddr_in은 bind 함수의 인자로 전달되는데, 매개변수 형이 sockaddr이므로 형 변환을 해야 한다.
struct sockaddr_in serv_addr;
if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
error_handling("bind() error");
- 구조체 sockaddr은 다양한 주소체계의 주소정보를 담을 수 있도록 정의됨
→ 그래서 IPv4의 주소정보를 담기가 불편함
→ 동일한 바이트 열을 구성하는 구조체 sockaddr_in이 정의되었으며, 이를 이용해서 쉽게 IPv4의 주소정보를 담을수 있다.
struct sockaddr
{
sa_family_t sin_family; // 주소체계(Address Family)
char sin_data[14]; // 주소 정보
};
3-3 네트워크 바이트 순서와 인터넷 주소 변환
1) CPU에 따라 달라지는 정수의 표현
- CPU에 따라서 데이터를 표현 및 해석하는 방식이 다름
(1) Big Endian(빅 엔디안) : 상위 바이트의 값을 작은 번지수에 저장
(2) Little Endian(리틀 엔디안) : 상위 바이트의 값을 큰 번지수에 저장
(3) 호스트 바이트 순서 : CPU별 데이터 저장방식을 의미
(4) 네트워크 바이트 순서 : 통일된 데이터 송수신 기준을 의미 / 빅 엔디안이 기준
2) 바이트 순서의 변환
- h : 호스트(host) 바이트 순서를 의미
- n : 네트워크 바이트 순서를 의미 → 내가 쓰는 컴퓨터가 빅 엔디안이든 리틀 엔디안이든 네트워크 바이트 순서로 통일
- s : 자료형 short를 의미
- l : 자료형 long을 의미
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
<예시>
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);
net_addr=htonl(host_addr);
printf("Host ordered port: %#x \n", host_port);
printf("Network ordered port : %#x \n", net_port);
printf("Host ordered address : %#lx \n", host_addr);
printf("Network ordered address : %#lx \n", net_Addr);
return 0;
}
3-4. 인터넷 주소의 초기화와 할당
1) 문자열 정보를 네트워크 바이트 순서의 정수로 변환
- "211.214.107.99"와 같이 점이찍힌 10진수로 표현된 문자열을 전달하면, 해당 문자열 정보를 참조하여 IP주소정보를 32비트 정수형으로 반환!
#include <arpa/inet.h>
in_addr_t inet_addr(const char * string);
→ 성공 시 빅 엔디안으로 변환된 32비트 정수 값, 실패 시 INADDR_NONE 반환
2) inet_aton
- 기능사응로 inet_addr 함수와 동일 → in_addr형 구조체 변수에 변환의 결과가 저장된다는 점이 다름
#include <arpa/inet.h>
int inet_aton(const char * string, struct in_addr * addr);
→ 성공 시 1(true), 실패 시 0(false) 반환
// string : 변환할 IP주소정보를 담고 있는 문자열의 주소 값 전달
// addr : 변환된 정보를 저장할 in_addr 구조체 변수의 주소 값 전달
3) inet_ntoa
- inet_aton 함수의 반대 기능 제공 → 네트워크 바이트 순서로 정렬된 정수형 IP주소정보를 우리가 눈으로 쉽게 인식할 수 있는 문자열의 형태로 변환
#include <arpa/inet.h>
char* inet_ntoa(struct in_addr adr);
→ 성공 시 변환된 문자열의 준소 값, 실패 시 -1 반환