크래프톤정글/CS:APP

[CS:APP] CH11 네트워크 프로그래밍

아람2 2024. 10. 26. 18:10
반응형

CH11 네트워크 프로그래밍 Network Programming 

모든 네트워크 응용들은 동일한 기본적인 프로그래밍 모델에 기초하고 있고,

비슷한 전체 논리 구조를 가지며, 동일한 프로그래밍 인터페이스를 사용한다 

11.1 클라이언트-서버 프로그래밍 모델

모든 네트워크 응용 프로그램은 클라이언트-서버 모델에 기초하고 있다

이 모델을 사용해서 응용은 한 개의 서버 Server 프로세스와 한 개 이상의 클라이언트 Client 프로세스로 구성된다 

서버는 일부 리소스를 관리하고, 이 리소스를 조작해서 클라이언트를 위한 일부 서비스를 제공한다 

 

클라이언트-서버 모델에서 근본적인 연산은 트랜잭션이다 

 

1. 클라이언트가 서비스를 필요로 할 때, 한 개의 요청 Request 을 서버로 보내는 것으로 트랜잭션을 시작한다

ex. 웹 브라우저가 파일을 필요로 할 때, 웹 서버로 요청을 보낸다 

2. 서버는 요청을 받고, 해석하고, 자신의 자원들을 적절한 방법으로 조작한다

ex. 웹 서버가 브라우저로부터 요청을 받을 때, 디스크 파일을 읽는다 (🐣 요청된 파일이 저장된 디스크 위치를 확인하고, 그 파일을 읽기 위해 디스크에 접근한다, 파일을 찾으면 그 위치에서 파일을 읽어서 메모리에 로드한다)

3. 서버는 응답 Response 을 클라이언트로 보내고, 그 후에 다음 요청을 기다린다

ex. 웹 서버는 이 파일을 다시 클라이언트로 돌려보낸다

4. 클라이언트는 응답을 받고 이것을 처리한다

ex. 웹 브라우저가 서버로부터 페이지르 한 개 받은 후, 이것을 스크린에 디스플레이한다

 

클라이언트와 서버는 프로세스이며, 이 컨텍스트에서 종종 불린 것처럼 머신이나 호스트는 아니라는 것을 인식하는 것이 중요하다

한 개의 호스트 (컴퓨터) 는 서로 다른 많은 클라이언트와 서버를 동시에 실행할 수 있으며,

클라이언트와 서버 트랜잭션은 동일하거나 다른 호스트에 존재할 수 있다 

11.2 네트워크

클라이언트와 서버는 종종 별도의 호스트에서 돌아가며, 컴퓨터 네트워크의 하드웨어 및 소프트웨어 자원을 사용해서 통신한다

호스트에게 네트워크는 단지 또 다른 I/O 디바이스이다, 아래 그림과 같이 데이터를 위한 소스와 싱크로 서비스한다

네트워크에서 수신한 데이터는 I/O 와 메모리 버스를 거쳐 어댑터에서 메모리로 (대게 DMA 전송으로) 복사된다

물리적으로 네트워크는 기하학적 위치로 구성된 계층구조 시스템이며, 하위 수준은 LAN Local Address Network 이다

가장 대중적인 LAN 기술은 현재까지는 이더넷 Ethernet 이고, 3 Mb/s 에서 10 Mb/s 로 진화하면서 안정화되었다 

 

이더넷 세그먼트 Ethernet Segment 는 몇 개의 전선들과 허브로 구성되며, 대역폭은 대게 100 Mb/s 나 1 Gb/s 이다 

한쪽 끝은 호스트의 어댑터에 다른 끝은 허브의 포트에 연결된다

허브는 각  포트에서 수신한 모든 비트를 종속적으로 다른 모든 포트로 복사하기 때문에 모든 호스트는 허브를 통해 전송된 모든 비트를 수신할 수 있다 

 

호스트는 프레임이라고 부르는 비트들을 세그먼트의 다른 호스트에 보낼 수 있다

각 프레임은 프레임의 소스와 목적지, 프레임의 길이를 식별할 수 있는 고정된 헤더 비트를 가지고 있고 그 뒤에 데이터 비트가 이어진다 

 

계층 구조의 상부에서 다수의 비호환성 LAN들은 라우터라고 부르는 특별한 컴퓨터에 의해서 연결될 수 있으며

라우터는 네트워크 간 연결을 구성한다 (상호연결 네트워크) 각 라우터는 이들이 연결되는 각 네트워크에 대해 어댑터(포트)를 가지고 있다 

라우터는 고속의 point-to-point 전화 연결을 할 수 있으며, 이들은 WAN Wide-Area Network 라고 하는 네트워크의 사례다 

 

internet 은, 다르고 비호환적인 기술을 갖는 여러 가지 LAN과 WAN들로 연결되어 있는데

각 호스트와 라우터에서 돌고 있는 프로토콜 소프트웨어의 계층으로 통신이 가능하다 

이 소프트웨어는 호스트들과 라우터들이 데이터를 전송하기 위해 협력하는 방법을 결정하는 프로토콜을 구현한 것이다 

이 프로토콜은 두 가지 기본 기능을 제공해야 한다

1) 명명법 Naming Scheme

호스트 주소를 위한 통일된 포맷을 정의한다, 각 호스트는 자신을 유일하게 식별하는 internet 주소 최소 한 개가 할당된다

2) 전달 기법 Delivery Mechanism

데이터 비트를 패킷이라고 부르는 비연속적인 단위로 묶는 통일된 방법을 정의한다

패킷패킷 크기와 소스 및 목적지 호스트 주소를 포함하는 헤더와 소스 호스트가 보낸 데이터 비트를 포함하는 데이터로 구성된다

설명은 컴퓨터시스템 책 P888-889 참고

이 예제는 internet 예제의 핵심을 보여주며, 캡슐화가 그 열쇠다 

11.3 글로벌 IP 인터넷 

글로벌 IP 인터넷은 internet 을 성공적으로 구현한 가장 유명한 것이다, 여러 다양한 형태가 존재하고 지속적으로 바뀌고 있지만

클라이언트-서버 응용 구조는 매우 안정적으로 남아 있다

각 인터넷 호스트는 TCP/IP Transmission Control Protocol/ Internet Protocol 을 구현한 소프트웨어를 실행하며 이것은 거의 모든 현대 컴퓨터 시스템에서 지원되고 있다, 인터넷 클라이언트와 서버는 소켓 인터페이스와 Unix I/O 함수들의 혼합을 사용해서 통신한다 

소켓 함수들은 일반적으로 시스템 콜로 구현되는데, 이 시스템 콜은 커널에서 트랩을 발생시키고, TCP/IP 에서 다양한 커널 모드 함수들을 호출한다

 

IP는 기본 명명법과 데이터그램이라고 하는 패킷을 한 인터넷 호스트에서 다른 호스트로 보낼 수 있는 배달 매커니즘을 제공한다 

다만 데이터그램을 잃어버리거나 중보되는 경우에 복구하려고 노력하지 않는, 안정적이지 못한 프로토콜이다 

UDP Unreable Datagram Protocol 는 프로세스에서 프로세스로 전송될 수 있다 

TCP 는 IP 위에 구현한 복잡한 프로토콜로 프로세스들 간에 안전한 완전 양방향 연결을 제공한다 

 

프로그래머의 관점에서, 인터넷을 다음과 같은 특징을 갖는 전 세계적인 호스트의 집합이라고 생각할 수 있다

* 호스트의 집합은 32비트 IP 주소 집합에 매핑된다

* IP 주소의 집합은 인터넷 도메인 네임 Internet Domain Name 이라고 부르는 식별자의 집합에 매핑된다 

* 하나의 인터넷 호스트의 프로세스는 연결을 통해서 다른 인터넷 호스트의 프로세스와 통신할 수 있다 

11.3.1 IP 주소

 

IP 주소는 비부호형 32비트 정수다, 네트워크 프로그램은 IP 주소를 IP 주소 구조체에 저장한다

인터넷 호스트들이 서로 다른 호스트 바이트 순서를 가질 수 있어 혼선이 생기는 경우를 대비하여 

TCP/IP가 모든 정수형 데이터 아이템에 대해서 통일된 네트워크 바이트 순서 (빅 엔디안 바이트 순서) 를 정의한다

IP 주소 구조체의 주소는 호스트 바이트 순서가 리틀 엔디안인 경우에도 항상 네트워크 바이트 순서 (빅 엔디안) 로 저장된다 

네트워크와 호스트 바이트 순서 간의 변환을 위해 Unix 는 다음과 같은 함수를 제공한다 

htonl 함수 - 비부호형 32비트 정수를 호스트 바이트 순서에서 네트워크 바이트 순서로 변환

ntohl 함수 - 비후호형 32비트 정수를 네트워크 바이트 순서에서 호스트 바이트 순서로 변환

* "n"은 네트워크 표현, "a"는 응용 표현, "to"는 ~로 를 나타낸다 

 

IP 주소는 대게 dotted-decimal 표기 형식으로 제시되며, 각 바이트가 십진수 값을 사용하고 점을 사용해서 구분한다 

응용프로그램들은 IP 주소와 dotted-decimal 스트링 사이를 inet-pton과 inet_ntop을 사용하여 상호 변환한다 

"n"은 network를 의미하고 "p"는 presentation을 의미한다, 이들은 32비트 IPv4 주소 (AF_INET4) 나 128비트 IPv6 주소 (AF_INET6) 를 처리할 수 있다 (이하 자세한 설명은 생략)

11.3.2 인터넷 도메인 이름 Internet Domain Name

인터넷 클라이언트와 서버는 서로 통신할 때 IP 주소를 사용하지만, 기억하기 어려워서

인터넷에서는 도메인 이름들의 집합을 IP 주소 집합으로 매핑하는 매커니즘과 함께 별도의 도메인 이름 집합을 정의한다

도메인 이름은 단어들의 배열로 (문자, 숫자, - 문자) 점으로 구분한다

 

도메인 이름들의 집합은 계층 구조를 형성하고 있으며, 각각의 도메인 이름은 계층 구조에서 자신의 위치를 인코드한다

계층 구조는 트리로 나타내며, 첫번째 단계는 이름이 없는 루트 노드이다

다음 계층은 ICANN Internet Corporation for Assigned Names and Number 라고 하는 비영리조직이 정의한 일단계 도메인 이름의 집합이다 ex. com, edu, gov, org, net 등

다음 계층에는 2단계 도메인 이름이 포함되며, 수많은 ICANN이 인정하는 대행사가 요청한 순서에 의해 그 이름이 할당된다

일단 한 조직이 2단계 도메인 이름을 받은 후에는 서브도메인 내에서 어떤 새로운 이름도 자유롭게 생성할 수 있다 

 

인터넷은 도메인 이름의 집합과 IP 주소 집합 사이에 매핑을 정의하며, 이 매핑은 DNS Domain Name System 에서 관리되어 왔다 

개념적으로 DNS 데이터베이스는 수백만 개의 호스트 엔트리로 구성되어 있으며,

이들 각각은 도메인 이름과 집합과 IP 주소 집합 사이의 매핑을 정의한다 

도메인 이름과 연관된 IP 주소를 표시하는 리눅스 NSLOOKUP 프로그램으로 DNS 매핑의 일부 특성을 조사할 수 있다

linux> nslookup localhost
Address: 127.0.0.1

도메인 이름과 IP 주소 사이에는 일대일 매핑이 존재할 수도 있고 (가장 간단한 경우)

다수의 도메인 이름이 동일한 IP 주소에 매핑될 수도 있고 (일부 경우) 

다수의 도메인 이름들이 다수의 IP 주소로 매핑될 수 있고 (대부분의 일반적인 경우)

일부 유효한 도메인 이름들이 어떤 IP 주소에도 매핑되어 있지 않을 수도 있다 

11.3.3 인터넷 연결

인터넷 클라이언트와 서버는 연결 Connection 을 통해서 바이트 스트림을 주고 받는 방식으로 통신하며

이 연결은 Point-to-point 연결이고, 데이터가 동시에 양방향으로 흐를 수 있다는 의미에서 완전방방향 full-duplex 이다 

소스 프로세스가 보낸 바이트 스트팀이 보낸 것과 동일한 순서로 목적지 프로세스에 수신된다는 의미에서 안정적이다 

 

소켓 Socket 은 연결의 종단점이다

각 소켓은 인터넷 주소와 16비트 정수 포트로 이루어진 소켓 주소를 가지고, address:port 로 나타낸다 

클라이언트의 소켓 주소 내의 포트는 연결 요청 시 커널이 자동으로 할당하며, 단기 ephemeral 포트라고 한다 

 

연결은 두 개의 종단점의 소켓 주소에 의해 유일하게 식별된다, 소켓 쌍은 tuple 로 나타낸다 

11.4 소켓 인터페이스

소켓 인터페이스는 네트워크 응용을 만들기 위한 Unix I/O 함수들과 함께 사용되는 함수의 집합이다 

전형적인 클라이언트-서버 트랜잭션의 문맥에서 소켓 인터페이스의 개요

11.4.1 소켓 주소 구조체

Linux 커널의 관점에서, 소켓은 통신을 위한 끝점이다

Unix 프로그램의 관점에서, 소켓은 해당 식별자를 가지는 열린 파일이다 

🐣 Linux 커널에서 소켓은 네트워크 통신을 위한 인터페이스, 소켓은 프로세스 간 통신을 위해 필요한 여러 정보를 포함하는 구조체

🐣 Unix 및 Linux 시스템에서 모든 I/O 자원은 파일 디스크립터로 추상화되고, 소켓도 일종의 파일로 취급된다

🐣 열린 파일이라는 말은, 파일 디스크립터를 통해 접근하고 조작할 수 있어서 열린 파일이라고 한 듯하다 

 

인터넷 소켓 주소는 sockaddr_in 타입의 16바이트 구조체에 저장되고, 

connect, bind, accept 함수는 프로토콜에 특화된 소켓 주소 구조체를 가리키는 포인터를 필요로 한다 

지금은 우리가 void * 를 사용하지만, 초기 소켓 인터페이스를 설계한 시점에는 void 개념이 없었기 때문에

이런 함수들은 sockaddr 구조체 포인터를 인수로 넘겨 받아 네트워크에서의 주소와 포트 정보를 처리할 수 있다 

이후 프로그래머들은 프로토콜에 특화된 구조체 포인터를 sockaddr 구조체로 형변환하여 사용할 수 있도록 정의되었다 

11.4.2 socket 함수 

클라이언트와 서버는 소켓 식별자를 생성하기 위해서 socket 함수를 사용한다 

만약 소켓을 끝점으로 만들고 싶다면, 다음과 같이 하드코드된 인자로 socket 함수를 호출한다

clientfd = Socket(AF_INET, SOCK_STREAM, 0);

AF_INET - 32비트 IP 주소를 사용하고 있다는 것을 나타낸다 

SOCK_STREAM - 소켓이 인터넷 연결의 끝점이 될 것이라는 것을 나타낸다 

socket 에 의해 리턴된 clientfd 식별자는 부분적으로 열린 것이며, 아직 읽거나 쓸 수 없다 

11.4.3 connect 함수 

클라이언트는 connect 함수를 호출해서 서버와의 연결을 수립한다 

connect 함수는 소켓 주소 addr 의 서버와 인터넷 연결을 시도하며, addrlen 은 sizeof(sockaddr_in) 이 된다 

connect 함수는 연결이 성공할 때까지 블록되어 있거나 (대기) 연결이 실패할 경우에는 에러가 발생한다 

성공이라면 다음과 같은 소켓 쌍으로 규정된다

(x:y, addr.sin_addr:addr.sin_port)

 

x 는 클라이언트의 IP 주소이고, y 는 클라이언트 호스트의 클라이언트 프로세스를 유일하게 식별하는 단기 포트다 

🐣 y 는 클라이언트 호스트의 포트 번호라고 이해하면 되고, 이 두 가지를 조합하여 특정 클라이언트의 IP 주소와

Port Number 를 통해 클라이언트 프로세스를 유일하게 식별할 수 있다는 말!

11.4.4 bind 함수 

남아 있는 소켓 함수 - bind, listen, accept - 는 서버가 클라이언트와 연결을 수립하기 위해 사용한다 

bind 함수는 소켓 식별자 sockfd 에 대해 주소 구조체 addr 를 바인딩하여 

커널이 이 소켓으로 들어오는 네트워크 요청을 처리할 수 있도록 설정하는 역할을 한다 

🐣 쉽게 말해서, 소켓 식별자의 IP Address 와 Port Number 를 할당한다 

11.4.5 listen 함수 

클라이언트는 연결 요청을 개시하는 능동적 개체이고, 서버는 클라이언트의 연결 요청을 기다리는 수동적 개체이다 

서버는 listen 함수를 호출해서 이 식별자를 클라이언트 대신에 서버가 사용하게 될 것이라고 알려준다 

listen 함수는 sockfd 를 능동 소켓에서 듣기 소켓으로 변환하며, 듣기 소켓은 클라이언트로부터의 연결 요청을 승락할 수 있다

backlog 인자는 커널이 요청들을 거절하기 전에 큐에 저장해야 하는 연결의 수에 대한 정보를 제공한다 

🐣 listen 함수로 클라이언트 연결 요청을 수신할 주비를 하고, 대기열 (큐) 을 설정하여 동시에 처리할 수 있는 클라이언트 수를 제한한다 

11.4.6 accept 함수 

서버는 accept 함수를 호출해서 클라이언트로부터의 연결 요청을 기다린다 

accept 함수는 클라이언트로부터의 연결 요청이 듣기 식별자 listenfd 에 도달하기를 기다리고

그 후에 addr 내의 클라이언트의 소켓 주소를 채우고, Unix I/O 함수들을 사용해서 

클라이언트와 통신하기 위해 사용될 수 있는 연결 식별자를 리턴한다 

듣기 식별자  연결 식별자 
클라이언트 연결 요청에 대해 끝점으로서의 역할  클라이언트와 서버 사이에 성립된 연결의 끝점 
한 번 생성 서버가 연결 요청을 수락할 때마다 생성 
서버가 살아있는 동안 계속 존재  서버가 클라이언트에 서비스하는 동안에만 존재 

 

11.4.7 호스트와 서비스 변환 

Linux 의 getaddrinfo 와 getnameinfo 는 네트워크 프로그래밍에서 주소와 이름 변환을 도와주는 함수들이다 

getaddrinfo 함수

호스트이름, 호스트주소, 서비스이름, 포트번호의 스트링 표시를 소켓 주소 구조체로 변환한다 

host 와 service (소켓 주소의 두 개의 구성 요소) 가 주어지면, getaddrinfo 각각 host 와 service 에 대응되는 소켓 주소 구조체를 가리키는 addrinfo 구조체의 연결 리스트를 리턴한다 

🐣 호스트 이름은 도메인, 서비스 이름은 포트 번호, 소켓 주소 구조체는 주소, 포트 등을 포함하는 데이터 구조 라고 생각하면 편하다 

getaddrinfo 함수는 주어진 호스트 이름과 서비스 이름을 사용해 해당 호스트와 서비스에 연결하기 위한 소켓 주소 정보를 찾고,

이 정보는 addrinfo 구조체의 연결 리스트로 반환되어, 나중에 소켓을 생성하고 연결하는 데 사용된다 

 

메모리 누수를 피하기 위해 응용 프로그램은 freeaddrinfo 를 호출하여 이 리스트를 반환해야 한다 

 

 

 

 

 

 

CS:APP 책 번역이 매우 불친절해서 내용이 정말 안 읽히는데

그래도 이렇게 복기하면서 한 번 더 짚고 넘어가는 게 좋지 않을까 생각했었다

근데 지금 와서 보니 좀 의미가 없는 것도 같아서 CS:APP 책은 그만 정리하고 

그냥 읽고 이해하는 것에 중점을 둬야겠다 

반응형