본문 바로가기
Programming/열혈 TCP, IP 소켓 프로그래밍(저자 윤성우)

Ch 03. 내용 확인문제

by minjunkim.dev 2020. 8. 5.

    모든 내용은 [윤성우 저, "열혈강의 TCP/IP 소켓 프로그래밍", 오렌지미디어] 를 기반으로 제 나름대로 이해하여 정리한 것입니다. 다소 부정확한 내용이 있을수도 있으니 이를 유념하고 봐주세요!


01. IP주소 체계인 IPv4와 IPv6의 차이점은 무엇인가? 그리고 IPv6의 등장배경은 어떻게 되는가?

 

1) IPv4(Internet Protocol version 4) : 4바이트 주소체계

2) IPv6(Internet Protocol version 6) : 16바이트 주소체계

- IPv6은 2010년을 전후로 IP주소가 모두 고갈될 것을 염려하여 만들어진 표준임


02. 회사의 로컬 네트워크에 연결되어 있는 개인 컴퓨터에 데이터가 전송되는 과정을,

IPv4의 네트워크 ID와 호스트 ID, 그리고 라우터의 관계를 기준으로 설명하여라.

 

1) 데이터는 먼저 네트워크 ID를 기준으로 특정 네트워크로 전송된다.

2) 데이터를 전송받은 라우터(or 스위치)는 호스트 ID를 기준으로 특정 호스트로 데이터를 전달한다.


03. 소켓의 주소는 IP와 PORT번호 두 가지로 구성된다. 그렇다면 IP가 필요한 이유는 무엇이고, PORT번호가 필요한 이유는 또 무엇인가? 다시 말해서, IP를 통해서 구분되는 대상은 무엇이고, PORT 번호를 통해서 구분되는 대상은 또 무엇인가?

 

1) IP의 네트워크 ID : 특정 네트워크를 구분

2) IP의 호스트 ID : 해당 네트워크에서 특정 호스트를 구분

3) PORT 번호 : 해당 호스트에서 특정 응용프로그램의 "소켓"을 구분 


04. IP주소의 클래스를 결정하는 방법을 설명하고, 이를 근거로 다음 IP주소들이 속하는 클래스를 판단해보자.

 

# IPv4 주소체계(총 4바이트)

- A 클래스 : 1바이트(네트워크ID) + 3바이트(호스트ID)
- B 클래스 : 2바이트(네트워크ID) + 2바이트(호스트ID)
- C 클래스 : 3바이트(네트워크ID) + 1바이트(호스트ID)
- D 클래스 : 4바이트(멀티캐스트 IP주소)

 

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

- 클래스 A의 첫번째 바이트 범위 : 0 - 127 => 상위 1비트가 항상 0
- 클래스 B의 첫번째 바이트 범위 : 128 - 191 => 상위 2비트가 항상 10
- 클래스 C의 첫번째 바이트 범위 : 192 - 223 => 상위 3비트가 항상 110

 

- 214.121.212.102 => 클래스 C

- 120.101.122.89 => 클래스 A

- 129.78.102.211 => 클래스 B


05. 컴퓨터는 라우터 또는 스위치라 불리는 물리적인 장치를 통해서 인터넷과 연결된다. 그렇다면 라우터 또는 스위치의 역할이 무엇인지 설명해보자.

 

    라우터는 데이터를 가장 효율적으로 전달하는 방법을 결정하고, 결정한 경로대로 데이터를 전송한다.


06. '잘 알려진 PORT(Well-known PORT)'는 무엇이며, 그 값의 범위는 어떻게 되는가? 그리고 알려진 PORT 중에서 대표적인 HTTP와 FTP의 PORT번호가 어떻게 되는지 조사해보자

 

1) 포트번호 0 - 1023까지는 "Well-known PORT"로 특정 프로그램에 할당되기로 예약되어 있음

2) HTTP 의 포트번호 : 80

3) FTP 의 포트번호 : 20(FTP 기본 데이터 전송) / 21(FTP 제어)


07. 소켓에 주소를 할당하는 bind 함수의 프로토타입은 다음과 같다

 

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

   그런데 호출은 다음의 형태로 이루어진다.

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

 

   여기서 serv_addr은 구조체 sockaddr_in 변수이다. 그렇다면 bind 함수의 프로토타입과 달리 구조체 sockaddr_in 변수를 사용하는 이유는 무엇인지 간단히 설명해보자

 

    구조체 sockaddr은 구조체 멤버 char sa_data[14]; 에 IP와 PORT번호를 모두 포함하고, 남은 부분은 0으로 채워야하는 불편함이 있다. 그러나 구조체 sockaddr_in 은 sockaddr과 다르게 IP와 PORT번호를 서로 다른 멤버에 할당하게끔 정의되어 있어 주소정보 초기화를 할때 편하다. 따라서 sockaddr_in 구조체로 주소정보를 초기화 후, 이를 sockaddr 구조체로 형변환하여 bind 함수가 요구하는 바이트 형태로 만들어 사용한다.

struct sockaddr

{

    sa_family_t sin_family; // 주소체계(Address Family)

    char sa_data[14]; // 주소정보

                      // IP주소와 PORT 번호를 포함하고, 남은 부분은 0으로 채울 것을 bind 함수가 요구

};
struct sockaddr_in
{
    sa_family_t sin_family; // 주소체계(Address Family)

    // (IPv4 전용 구조체라고 했는데) 굳이 별도로 저장하는 이유는..?

    // (struct sockaddr *)&sockaddr_in 형태로 형변환을 하여 주소정보를 전달하게 되는데

    // sockaddr은 IPv4의 주소 정보만을 담기 위해 정의된 구조체가 아니기 때문


    uint16_t sin_port; // 16비트(2바이트) TCP/UDP PORT 번호 : "네트워크 바이트 순서"로 저장해야 함
    struct in_addr sin_addr; // 32비트(4바이트) IP주소 : "네트워크 바이트 순서"로 저장해야 함
    char sin_zero[8]; // 실질적으로 사용되지 않음(단, 반드시 0으로 채워야 함)
};

08. 빅 엔디안과 리틀 엔디안에 대해서 설명하고, 네트워크 바이트 순서가 무엇인지, 그리고 이것이 필요한 이유는 또 무엇인지 설명해보자.

 

- CPU에 따라 데이터를 메모리에 저장하는 방식(호스트 바이트 순서)이 달라질 수 있음
1) 빅 엔디안 : 상위 바이트 값을 작은 번지수에 저장
2) 리틀 엔디안 : 상위 바이트의 값을 큰 번지수에 저장
- 인텔, AMD 계열의 CPU는 리틀 엔디안 기준으로 데이터를 정렬함

- CPU에 따라 호스트 바이트 순서가 달라 데이터 송수신시에 문제가 발생할 수 있음

 

# 네트워크 바이트 순서의 약속 : "빅 엔디안 방식으로 통일"
=> 네트워크상으로 데이터를 전송할 때는 데이터의 배열을 "빅 엔디안 기준으로 변경"해서 송수신하기로 약속


09. 빅 엔디안을 사용하는 컴퓨터에서 4바이트 정수 12를 리틀 엔디안을 사용하는 컴퓨터에게 전송하려 한다. 이때 데이터의 전송과정에서 발생하는 엔디안의 변환과정을 설명해보자.

 

그림에서,

(상위 바이트) <------------------> (하위 바이트)

(작은 번지수) <------------------> (큰 번지수)

 

00000000 00000000 00000000 00001100(빅 엔디안) => 00001100 00000000 00000000 00000000(리틀 엔디안)


10. '루프백 주소(loopback address)'는 어떻게 표현되며, 의미하는 바는 무엇인가? 그리고 루프백 주소를 대상으로 데이터를 전송하면 어떠한 일이 벌어지는가?

 

    루프백 주소는 호스트 자신의 주소를 의미한다. "127.0.0.1"로 약속되어있다. 루프백 주소로 데이터를 전송하면, 전송된 데이터는 데이터를 전송한 컴퓨터로 다시 수신된다.


[출처] : 윤성우 저, "열혈강의 TCP/IP 소켓 프로그래밍", 오렌지미디어