팥빵 먹으면서 코딩하는 블로그

03-2. [Linux/Ubuntu] 네트워크 프로그래밍 - 주소체계와 데이터 정렬 본문

카테고리 없음

03-2. [Linux/Ubuntu] 네트워크 프로그래밍 - 주소체계와 데이터 정렬

김팥빵_ 2025. 3. 21. 17:19

주소체계와 데이터 정렬

  • 인터넷 주소( = ip주소)
    • 인터넷상에서 컴퓨터를 구분하는 목적으로 사용되는 주소
    • 1. 네트워크 주소와 2. 호스트 주소로 나뉨
    • subnet mask -> 네트워크 주소로 네트워크를 찾고, 호스트 주소를 사용해 해당 네트워크에서의 호스트를 검색함
    • IPv4 인터넷 주소 체계에 따라 / 네트워크 id와 호스트 id의 사용할 수 있는 크기가 달라짐

IPv4 인터넷 주소의 체계
인터넷 주소의 역할

  • 클래스 별 네트워크 주소와 호스트 주소의 경계
    • 클래스별 주소 범위
    • 특수 범위 주소 
      • local loopback -> 127.0.0.1 : 본인 컴퓨터 주소
      • 멀티캐스트 주소는 별도의 주소를 쓴다 : 클래스 D

 

 

  • Port 번호
    • IP 주소 : 컴퓨터를 구분하는 용도로 사용
    • Port 번호 
      • 소켓(응용프로그램)을 구분하는 용도로 사용
      • 하나의 프로그램 내에서는 둘 이상의 소켓이 존재할 수 있음
        • ex. 원격접속 -> 예를 들어, 원격접속의 기능에 따라 4개의 포트가 할당됨
      • Port 번호는 16비트로 표현 : 0 ~ 65535 이하
      • Well-known Port 번호 : 0 ~ 1023 사이의 이미 용도가 정해진 포트 번호
        • 우리가 쓸 수 없음. 미리 할당되어 있으므로 우리가 만든 응용 프로그램에 사용할 수 없음
        • 그래서 우리가 9천번대 ex. 9190 포트번호...같은 걸 쓰는 거임

Well-known port (0~1023) 예시

 

  • IPv4 주소 표현을 위한 구조체
    • IP 주소와 Port 번호는 sockaddr_in 구조체 변수를 이용해 표현
struct sockaddr_in
{
	sa_family_t		sin_family;	// 주소체계
	uint16_t		sin_port;	// Port 번호
	struct in_addr		sin_addr;	// 32비트 IP 주소
	char			sin_zero[8];	// 사용되지 않음
};

struct in_addr	//32비트 IP 주소
{
	in_addr_t	s_addr;
};

 

  • 구조체 sockaddr_in의 멤버에 대한 분석
    • sockaddr_in 구조체 멤버
      1. sin_familiy
        • 주소체계 저장 : AF_INET
      2. sin_port
        • 16비트 Port 번호 저장
        • 네트워크 바이트 순서로 저장
      3. sin_addr
        • 32비트 IP 주소 저장
        • 네트워크 바이트 순서로 저장
        • 멤버 sin_addr의 구조체 자료형 in_addr : 32비트 정수형
      4. sin_zero[8]
        • ***반드시 0으로 초기화***
        • sockaddr 구조체와 크기를 맞추기 위해 사용
  •  구조체 sockaddr_in의 활용
    1. bind()함수의 인자로 전달
      • bind() 함수의 매개변수 타입이 sockaddr이므로 형변환이 필요
    2. d

 

  • 바이트 순서 (order)와 네트워크 바이트 순서
    • 빅 에디안 (Big Edian)
      • 상위 바이트의 값을 작은 번지수에 저장 (상위 바이트의 값을 앞에 위치)
    • 리틀 에디안 (Little Edian)
      • 하위 바이트의 값이 작은 번지수에 저장 (상위 바이트의 값을 큰 번지수에 저장)
      • ex. Intel, Apple silicon ...
    • 네트워크 바이트 순서 (Network Byte Order)
      • 통일된 데이터 송수신 기준을 의미
      • Big Edian 사용
    • 데이터 송수신 과정
      • 바이트 단위(바이트 스트림)로 데이터를 전송
      • 바이트 변환 과정이 필요 없음
        • ex. 
        • serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
        • serv_addr.sin_port=htons(atoi(argv[1]));
        • htonl, htons : ip주소와 port번호를 / little edian을 big edian으로 바꾸는 함수
        • 따라서 네트워크 정보만 바꾸므로 / 실제 데이터는 변환 과정이 필요 없다!

big edian과 little endian의 차이
big edian에서 little edian으로의 데이터 전송 및 해석방법

  • htons() : host to network 방향으로 바꿔줌
  • ntohs() : network to host 방향으로 바꿔줌

Little edian -> Little edian 통신
Big edian -> Little edian 통신

 

  • 바이트 순서의 변환 (Edian Conversions)
    • 바이트 순서 변환 함수 
      • 바이트 순서 변환은 sockaddr_in 구조체 변수에 주소 정보를 저장할 때만 사용하면 됨

바이트 순서 변환 함수들

  • htons에서 
    • h는 호스트 ~의미
    • n은 네트워크
    • s는 자료형
  • htonl에서 l은 자료형 long을 의미
  • 바이트 변환의 예시
#include	<stdio.h>
#include	<arpa/inet.h>
typedef unsigned short u16;
typedef unsigned long u32;
int main(int argc,	char *argv[])
{
				u16	host_port=0x1234;
				u16	net_port;
				u32	host_addr=0x12345678;
				u32	net_addr;
				net_port=htons(host_port);	//htons 함수로 바이트 변환
				net_addr=htonl(host_addr);	//htonl 함수로 바이트 변환
				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;
}

 

 

바이트 변환 함수

  • 1. inet_addr() 함수
    • inet_addr(const char *string) 
    • client 쪽에서 사용
    • "211.214.107.99”와 같이 10진수(dotted decimal)형태로 표시된 문자열을 전달
    • 빅 엔디안의 "정수"로 변환해줌
#include <arpa/inet.h>
in_addr_t inet_addr(const char* string);
-> 성공 시 빅 엔디안으로 변환된 32비트 정수값, 실패 시(비정상적인 주소일 경우) INADDR_NONE 반환 ***
-> 비정상적인 주소 ex. "1.2.3.256"

 

  • in_addr_t 타입 : uint32_t 형태(32비트)

 

  • 2. inet_aton (문자열 형태 -> in_addr 구조체로 변환)
    • inet_aton() 함수
      • inet_addr() 함수와 동일 기능
      • 단, in_addr 구조체 변수에 변환 결과가 저장되는 점이 inet_addr()과 다름
      • 한마디로 파라미터만 달라졌단 뜻
#include <arpa/inet.h>

int inet_aton(const char *string, struct in_addr *addr);
-> *string에서 *addr로 변환 및 결과를 저장한다.
-> 성공 시 1(true), 실패 시 0(false) 반환

-> string : 변환할 IP 주소 정보를 담고 있는 문자열
-> ddr : 변환될 정보를 저장할 in_addr 구조체 변수의 주소값 전달


/***예시***/
char *addr="127.232.124.79"; //addr : 이 문자열을 가지고 있는 주소값
struct sockaddr_in addr_inet;

inet_aton(addr,	&addr_inet.sin_addr)) //addr주소의 문자열을 &addr_inet.sin_addr로 전달
printf("Network	ordered	integer	addr:	%#x	\n",	addr_inet.sin_addr.s_addr)

 

  • 3. inet_ntoa (정수 형태 -> 문자열 형태로 변환)
    • inet_ntoa() 함수 
      • 네트워크 바이트 순서로 정렬된 정수형문자열 형태로 변환
      • inet_aton() 함수의 반대 기능
#include <arpa/inet.h>

char *inet_ntoa(struct in_addr addr);
-> 성공 시 변환된 "문자열의 주소값", 실패 시 -1 반환
  • 내부적으로 static 변수(char buffer[18])에 변환된 주소 값이 저장된다.
    • 프로그램이 종료될 때까지 buffer 변수의 메모리는 유지됨
  • 새로운 주소를 이용해 inet_ntoa()함수를 다시 호출할 경우, 
    • buffer가 가리키는 메모리(주소)의 값은 변경됨
    • 기존이 buffer를 가리키고 있던 포인터 변수 *str_ptr의 값이 변경됨
    • 따라서, 두 번째 inet_ntoa() 함수 호출시에는 리턴값을 받는 변수 사용 안함
  • 전역 static 변수(참고)
    • 해당 소스파일 내부에서만 사용 가능하고 다른 파일에서 사용 못함
    • extern 사용 안됨!
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);	//inet_ntoa 함수 내에서 메모리가 할당됨 -> 메모리가 없는 *str_ptr에 저장
strcpy(str_arr,	str_ptr);	// str_ptr의 값을 str_arr로 복사
printf("Dotted-Decimal notation1: %s\n", str_ptr);

str_ptr = inet_ntoa(addr2.sin_addr);	// addr2.sin_addr : 내부 전역 buffer의 값 변경
printf("Dotted-Decimal notation2: %s\n", str_ptr);	// str_ptr : return값이 없음에도 변경되어 있음

 

인터넷 주소의 초기화

  • 인터넷 주소의 초기화
    • 서버에서 주소 정보를 설정하는 이유 :
      • “IP 211.217.168.13, PORT 9190으로 들어오는 데이터는 내게로 다 보내라!”
    • 클라이언트에서 주소 정보를 설정하는 이유 :
      • “IP 211.217.168.13, PORT 9190으로 연결을 해라!”
    • 일반적인 인터넷 주소 초기화 과정
struct sockaddr_in addr;
char *serv_ip ="211.217.168.13"; //	서버의 IP	주소 문자열
char *serv_port =	"9190"; // Port	번호 문자열
memset(&addr,	0,	sizeof(addr)); //	구조체의 모든 멤버를 0으로 초기화
addr.sin_family =	AF_INET; //	주소 체계 지정
addr.sin_addr.s_addr =	inet_addr(serv_ip); //	IP	주소를 정수형으로 변환 및 저장
addr.sin_port =	htons(atoi(serv_port)); //	Port	번호를 정수형으로 변환 및 저장

 

  • INADDR_ANY
    • 서버 소켓의 주소 할당
    • 이게 들어갈 곳에 하드코딩하면 다시 컴파일해서 다시 실행시켜야 하는 불편함이 있음
    • 따라서 자동으로 할당해주는 INADDR_ANY를 사용

 

소켓에 인터넷 주소 할당

  • 소켓에 인터넷 주소 할당
    • bind()
  • 소켓에 인터넷 주소 할당 과정
    • 코드
  •