윤성우의 열혈 TCP/IP Ch.3

KSH·2022년 9월 13일
0

열혈강의 TCP/IP

목록 보기
3/4

주소체계와 데이터 정렬


1. 소켓에 할당되는 IP주소와 PORT 번호

Internet protocol과 PORT 번호
넘버링 체계가 바뀌었지만 그냥 그러려니 해주시면... ㅎㅎ

참고자료
http://www.orentec.co.kr/teachlist/TCP_IP_1/teach_sub1.php

1. 인터넷 주소


1.1 인터넷 주소의 종류

  • IPv4 : Internet Protocol version 4, 4바이트 주소체계
  • IPv6 : Internet Protocol version 6, 16바이트 주소체계

1.2 IPv4 주소체계

- 클래스 A : 네트워크ID. 호스트ID . 호스트ID . 호스트ID	-> 각 1바이트
- 클래스 B : 네트워크ID.네트워크ID. 호스트ID . 호스트ID 	-> 각 1바이트
- 클래스 C : 네트워크ID.네트워크ID.네트워크ID. 호스트ID 	-> 각 1바이트
- 클래스 D : 네트워크ID.네트워크ID.네트워크ID.네트워크ID 	-> 각 1바이트

1.3 IP주소 기반의 데이터 전송과정

1.4 라우터와 스위치

  • 공통적 특징
    외부로부터 수신된 데이터를 호스트에 전달하고, 호스트가 전달하는 데이터를 외부로 송신해주는 물리적 장치

  • 차이점
    라우터보다 기능적으로 다른 것을 스위치라고 부른다.

1.5 클래스 별 네트워크 주소와 호스트 주소의 경계

  • 클래스 A의 첫 번째 바이트 범위 : 0이상 127 이하 -> 첫번째 비트는 항상 0으로 시작
  • 클래스 B의 첫 번째 바이트 범위 : 128이상 191 이하 -> 첫 두 비트는 항상 10으로 시작
  • 클래스 C의 첫 번째 바이트 범위 : 192이상 223 이하 -> 첫 세 비트는 항상 110으로 시작

1.6 소켓의 구분에 활용되는 PORT 번호

  • IP
    컴퓨터를 구분하기 위한 목적으로 존재한다.

  • PORT
    같은 컴퓨터 내부에서 프로그램을 구분하기 위해 사용되는 정보

  • P2P

2. 주소정보의 표현


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

  1. POSIX 자료형
    자료형 이름 자료형에 담길 정보 선언된 헤더파일
    int8_t
    uint8_t
    int16_t
    uint16_t
    int32_t
    uint32_t
    singned 8-bit int
    unsigned 8-bit int (unsigned char)
    signed 16-bit int
    unsinged 16-bit int (unsigned char)
    signed 32-bit int
    unsigned 32-bit int (unsigned char)
    sys/types.h
    sa_family_t
    socklen_t
    주소체계(address family)
    길이정보(length of struct)
    sys/socket.h
    in_addr_t
    in_port_t
    IP 주소정보, uint32_t로 정의되어 있음
    PORT 번호정보, uint16_t로 정의되어 있음
    netinet/in.h

  1. struct sockaddr_in 구조체
  • bind 함수에 주소 정보를 전달하는 용도

  • 구조체 원본

struct sockaddr_in {
	sa_family_t		sin_family; 	-> 주소체계(ex. PF_INET) 
    uint16_t		sin_port;		-> 16비트 TCP/UDP PORT 번호
    struct in_addr	sin_addr;		-> 32비트 IP 주소
    char			sin_zero[8];	-> 사용되지 않음
};
  • sin_addr 구조체 원본
struct in_addr{
	in_addr_t	s_addr;	->32비트 IPv4 인터넷 주소
};

2.2 구조체 sockaddr_in 멤버에 대한 분석

  1. 멤버 sin_family
    주소체계(Address Family) 의 미
    AF_INET
    AF_INET6
    AF_LOCAL
    IPv4 인터넷 프로토콜에 적용하는 주소체계
    IPv6 인터넷 프로토콜에 적용하는 주소체계
    로컬통신을 위한 유닉스 프로토콜의 주소체계

  2. sin_port
    16비트 PORT 번호를 저장한다. 중요한건 네트워크 바이트 순서로 저장된다
  3. sin_addr
    32비트 IP주소를 저장한다.
  4. sin_zero
    개발자가 사용에 있어 알아야할 특별한 의미는 없다. sockaddr_in 구조체의 크기를 sockaddr에 일치시키기 위해 들어간 멤버, 중요한건 항상 0으로 채워야 한다는 것이다.
  • sockaddr_in 구조체

구조체 원형

struct sockaddr {
	sa_family_t sin_family;	-> 주소체계
    char		sa_data[14];-> 주소정보
};

3. 네트워크 바이트 순서와 인터넷 주소 변환

컴퓨터의 하드웨어에 따라서, 혹은 네트워크에 따라서 바이트(데이터)의 저장 순서가 달라진다


3.1 바이트 순서와 네트워크 바이트 순서

  • 빅엔디안(Big Endian)
    상위 바이트값을 작은 번지수에 저장하는 방식
    0x20번지0x21번지0x22번지0x23번지>
    정수 0x12345678
    0x120x340x560x78

  • 리틀 엔디안
    상위 바이트 값을 큰 번지수에 저장하는 방식
    0x20번지0x21번지0x22번지0x23번지>
    정수 0x12345678
    0x780x560x340x12

네트워크 상에서는 빅 엔디안으로 통일되어 있다
Intel 계열 CPU는 리틀 엔디안을 사용한다.


3.1 바이트 순서의 변환(Endian Conversion)

  • 기본 규칙
    htons에서의
    h는 호스트(host) 바이트 순서를 의미한다.
    n은 네트워크(network) 바이트 순서를 의미한다.

  • 변환 함수 종류

  1. unsigned short htons(unsigned short);
  2. unsigned short ntohs(unsinged short);
  3. unsigned long htonl(unsigned long);
  4. unsigned long ntohl(unsigned long);

4. 인터넷 주소의 초기화 할당


4.1 문자열 정보를 네트워크 바이트 순서의 정수로 변환하기
1. in_addr_t inet_addr() 함수

i. 헤더

#include<arpa/inet.h>

ii. 함수 원형

in_addr_t inet_addr(const char* string);

iii. 결과

  • if 성공 : 빅 엔디안으로 변환된 32비트 정수 값
  • if 실패 : INADDR_NONE반환

iv. 추가 기능

  • IP주소가 유효하지 않을 경우 오류검출을 지원한다.

2. int inet_aton() 함수

문자열 형태의 IP 주소를 네트워크 바이트 순서로 정렬 후 반환하는 함수

i. 헤더

#include<arpa/inet.h>

ii. 함수 원형

int inet_aton(const char* string, struct in_addr* addr);

iii. 파라미터

const char* string 	: 변환할 IP주소를 담고 있는 문자열의 주소 값 전달
strcut in_addr* addr: 변환된 정보를 저장할 in_addr 구조체 변수의 주소 값 전달

iv. 결과

  • 성공시 : 1(TRUE) return
  • 실패시 : 2(FALSE) return
3. char* inet_ntoa() 함수

i. 헤더

#include<arpa/inet.h>

ii. 함수 원형

char* inet_ntoa(struct in_addr adr);

iii. 파라미터

struct in_addr adr	: 변환할 주소 값

iv. 결과

  • if 성공 : 변환된 문자열의 주소값 return
  • if 실패 : 실패시 -1 return

4.2 인터넷 주소의 초기화

  1. 초기화 예시코드
    개요: 필요한 정보를 담은 변수를 선언 후 -> 구조체 addr에 하나씩 넣어 초기화 실시
stuct sockaddr_in addr;					-> 구조체 선언
char* serv_ip="211.277.168.13";			-> IP주소 문자열 선언
char* serv_port ="9190";				-> PORT번호 문자열 선언
memset(&addr, 0, sizeof(addr));			-> 구조체 변수 addr의 모든 멤버 0으로 초기화
addr.sin_family = AF_INET;				-> 구조체 멤버로 주소체계 지정
addr.sin_addr.s_addr = inet_addr;		-> 문자열 기반의 IP주소 초기화
addr.sin_port = htons(atoi(serv_port));	-> 문자열 기반의 PORT번호 초기화

여기서는 변수에 저장된 내용을 가져오는 방식이지만
main 함수의 argv[] 파라미터를 가져와서 터미널 옵션으로 받아올 수 있다.

4.3 클라이언트의 주소정보 초기화

  • bind() 함수
    서버의 외침, 참고로 클라이언트는 connect 함수

4.4 INADDR_ANY

  • 상수
  • 컴퓨터의 IP가 자동으로 초기화되어 있다.
  1. 사용 예시
addr.sin_addr.s_addr=htonl(INADDR_ANY)

4.5 소켓에 인터넷 주소 할당하기

  1. bind() 함수

i. 헤더

#include<sys/socket.h>

ii. 함수 원형

int bind(int sockfd, struct sockaddr* myaddr, socklen_t addrlen);

iii. 파라미터

int sockfd				: 주소정보를 (IP, PORT)를 할당할 소켓의 파일 디스크립터
struct sockaddr* myaddr	: 할당하고자 하는 주소정보를 지니는 구조체 변수의 주소값
socklen_t addrlen		: 두번째 인자로 전달된 구조체 변수의 길이정보

iv. 결과

  • if 성공 : 0 return
  • if 실패 : -1 return

v. 용례

bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_adr));

5. 윈도우 기반으로 구현하기


5.1 htons, htonl의 윈도우 기반 사용

  • WSAStartup, 그를 위한 winsock2.h 헤더를 요구하는 것외에는 리눅스와 큰 차이가 안난다.

5.2 함수 inet_addr, inet_ntoa 윈도우 기반 사용

  • inet_ntoa는 윈도우 기반에선 존재하지 않는다.

5.3 윈도우에서 소켓에 인터넷 주소 할당하기
과정은 리눅스와 동일하나 예시 코드 할당

  1. 예시 코드
SOCKET servSock;
struct sockaddr_in servAddr;
char* servPort="9190";

servSock = socket(PF_INET, SOCK_STREAM, 0);	-> 서버 소켓 생성

주소정보 초기화부분
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(servPort);

bind(servSock, (struct sockaddr*)&servAddr, sizeof(servAddr)); -> 초기화된 주소를 할당

5.4 WSAStringToAddress & WSAAddressToString

inet_ntoa, inet_addr을 대체하는 윈도우즈 함수, 기능적으론 더 넓은 부분을 커버 가능하다.

  1. WSAStringToAddress() 함수

주소정보를 나타내는 문자열을 구조체 형태로 바꿀 때, 위의 예시코드에서 주소정보 초기화 부분을 함수 하나로 해결한다.

i. 헤더

#include<winsock2.h>

ii. 함수원형

INT WSAStringToAddress(	LPTSTR AddressString, 
						INT AddressFamily, 
                        LPWSAPROTOCOL_INFO lpProtocolInfo,
                        LPSOCKADDR LPaDDRESS,
                        LPINT lpAddressLength
                        );

iii. 파라미터

LPSTR				AddressString : IP와 PORT번호를 담고 있는 문자열의 주소값 전달
INT					AddressFamily : 첫번째 인자로 전달된 주소정보가 속하는 주소체계 정보 전달
LPWSAPROTOCOL_INFO	lpProtocolInfo : 프로토콜 프로바이더 설정, 일반적으로 NULL 전달
LPSOCKADDR			lpAddress	   : 주소 정보를 담을 구조체 변수 값 전달
LPINT				lpAddressLength: 네번째 인자로 전달된 주소 값의 변수 크기를 담고 있는 변수의 주소값 전달

iv. 결과

  • if 성공 : O return
  • if 실패 : SOCKET_ERROR return
  1. WSAAddressToString() 함수

위의 함수와 반대로 구조체를 문자열로 바꾼다.

i. 헤더

include<winsock2.h>

ii. 함수 원형

INT WSAAddressToString(	LPSOCKADDR lpsaAddress,
						DWORD dwAddressLength,
                        LPWSAPROTOCOL_INFO lpProtocolInfo,
                        LPTSTR lpszAddressString,
                        LPDWORD lpwAddressStringLength
                        );

iii. 파라미터

LPSOCKADDR			lpsaAddress			: 문자열로 변환할 주소정보를 지니는 구조체 변수의 주소 값 전달
DWORD				dwAddressLength		: 첫번째 인자로 전달된 구조체 변수의 크기 전달
LPWSAPROTOCOL_INFO	lpProtocolInfo		: 프로토콜 프로바이더 설정, 일반적으로 NULL 설정
LPSTR				lpszAddressSTring	: 문자열로 변환된 결고라르 저장할 배열의 주소 값 전달
LPDWORD				lpdwAddressStringLength: 네번째 인자로 전달된 주소 값의 배열 크기를 담고 있는 변수의 주소 값 전달

iv. 결과

  • if 성공 : 0 return
  • if 실패 : SOCKET_ERROR return
profile
대충 개발자 비슷한거

0개의 댓글