VI : 웹 서버에 도착하여 응답 데이터가 웹 브라우저로 돌아간다
1% 네트워크 원리 을 읽고 정리한 문서입니다 ;)
서버의 개요
서버 머신은 용도에 따라 다양한 종류가 있으며, 하드웨어나 OS 부분은 클라이언트와 다른 것도 있지만, 네트워크에 대한 장비와 구성은 클라이언트와 조금도 다르지 않다.
사용하는 방법까지 같은 것은 아닌데, 서버의 어플리케이션은 동시에 다수의 클라이언트와 대화해야 하기 때문이다.
하나의 프로그램으로 여러 클라이언트들의 상태를 처리하기에는, 어느 클라이언트와 어디까지 대화가 진행되고 있는지를 파악해야 하기 때문에 쉽지 않다.
따라서, 클라이언트가 접속할 때마다 새로 서버 프로그램을 작동하여 서버 어플리케이션과 클라이언트를 1:1로 대화시키는 것이 일반적이다.
서버 프로그램을 접속을 기다리는 부분과 클라이언트와 대화하는 부분으로 나누어 만들고, 서버 프로그램이 초기화 후 접속을 기다리고 나서, 클라이언트가 접속했을 때 대화하는 부분을 실행시키고 그곳에 접속이 끝난 소켓을 전달해주는 식이다.
이는 서버 OS가 멀티태스크 또는 멀티스레드라는 기능에 의해 다수의 프로그램을 동시에 함께 작동시킬 수 있는 성질을 기반으로 한다.
다만 이 방법은 클라이언트가 접속했을 때 새로 프로그램을 기동하는 부분에서 다소 시간이 걸리고 응답 시간이 추가로 소요되기에, 미리 클라이언트와 대화하는 프로그램을 여러 개 준비해 놓고 여기에 접속한 소켓을 건네주는 방법도 있다.
서버 측의 동작은 다음 순서에 따른다.
socket
을 호출하여 소켓을 생성하는데, 이는 클라이언트와 같다.bind
를 호출하여 소켓에 포트 번호를 기록하고,listen
을 호출하여 소켓에 접속하기를 기다리는 상태라는 제어 정보를 기록한다.accept
를 호출하여 접속을 접수하고, 이는 실제로 접속이 이루어질 때 까지 어플리케이션을 쉬는 상태로 만든다.- 이 상태에서 만일 접속이 이루어진다면, 접속 대기의 소켓을 복사한 뒤 그곳을 통해 해당 클라이언트와 소켓으로 연결하고, 클라이언트와 대화하는 부분을 기동한다.
- 이처럼 기존 접속 대기 소켓을 클라이언트와 연결하지 않고, 새 소켓으로 복사하는 이유는 다음 접속을 곧이어 바로 받을 수 있게 하기 위함이다.
새 소켓을 만들 때 당연히 접속 대기 포트와 같은 포트 번호가 할당되어야 연결이 유지되지만, 이렇게 된다면 포트 번호만으로는 TCP 패킷이 도착했을 때 어느 소켓에서 대화하고 있는 것인지 판단할 수 없다.
따라서 패킷이 도착하면 소켓을 지정할 때 송수신측 IP주소와 송수신측 포트 번호라는 네 가지 항목을 사용해서 판별하게 된다.
접속 대기의 소켓에는 아직 클라이언트의 IP, 포트 정보가 없고 이 네 가지 정보보다는 디스크립터라는 하나의 정보로 소켓을 식별하는 것이 간단하기에, 어플리케이션에서 식별은 디스크립터로 항상 이루어진다.
정리
- 서버는
bind
,listen
,accept
를 호출하여 접속을 받아들이게 되며, 접속을 받아들이는 부분과 실제 클라이언트와 어플리케이션이 대화하는 부분을 1:N 구조로 만드는 것이 일반적이다. accept
는 접속 대기 소켓을 복사하여 그곳에 클라이언트를 연결시킴으로서 곧바로 접속을 이어 받을 수 있도록 한다.
서버의 수신 동작
서버의 수신 동작은 패킷의 신호를 LAN 어댑터에서 수신하고 디지털 데이터로 바꾸는 것에서 시작한다.
LAN을 흐르는 신호에서 클록 신호를 추출하여 타이밍을 계산하고, 신호를 읽어와 디지털 데이터를 만들고, FCS 를 이용해 오류 유무를 검사하며, 수신처 MAC 주소가 자신이 맞는지 확인한다.
이 작업은 LAN 어댑터의 MAC 부분이 실행하며, 이 작업이 완료되면 LAN 어댑터의 내부 버퍼 메모리에 디지털 데이터가 저장되고, CPU에 인터럽트를 발생시킨다.
이로서 CPU는 랜 드라이버를 통해 이 내부 버퍼 메모리에서 수신한 패킷을 추출하게 되고, MAC 헤더의 타입에 따라 프로토콜을 판별하고, (일반적으로 OS를 통해) TCP/IP의 프로토콜 스택을 호출하여 이곳에 패킷을 건네준다.
프로토콜 스택에서는 IP 담당 부분이 동작하여 IP헤더를 점검하여 수신처 IP가 맞는지 조사하고, 아니라면 라우팅을 시도한다.
이후 IP 계층에서 fragmentation이 이루어졌는지 조사하고, 분할된 패킷을 다시 리어셈블링하게 된다. 이후 IP 헤더의 프로토콜 번호에 따라 윗 계층의 프로토콜 스택을 호출한다.
TCP 담당 부분은 만일 TCP 헤더에 있는 SYN 이라는 컨트롤 비트가 1인지 조사하여, 연결을 시도하는 패킷인지 조사한다. 만일 그렇다면, 패킷의 수신처 포트와 같은 번호를 할당한, 접속 대기 상태의 포트가 있는지 조사하고, 없다면 에러 메시지를 회신한다.
만일 접속 대기 포트가 있다면 이를 위한 새 소켓을 만들며 필요한 정보들을 복사해 넣는다. 이후 패킷을 받았음을 알리는 ACK값, 시퀀스 번호의 초기값, 윈도우 크기를 넣은 TCP 헤더를 만들어 클라이언트측으로 회신한다.
이를 클라이언트가 받았다면 또다시 ACK 신호가 되돌아올 것이고, 이로서 접속 동작은 완료된다.
이 때 서버측 어플리케이션이 호출한 accept
에 해당 소켓의 디스크립터가 전달되고, 서버 어플리케이션의 해당 부분 처리 코드가 작동하게 된다.
TCP로 들어온 패킷이 만일 데이터 패킷이었다면, 도착한 패킷이 어느 소켓에 해당하는지 송수신처 IP, 포트를 통해 찾아내고, 해당 소켓의 진행 상황 데이터와 패킷의 데이터를 비교하여 이상은 없는지 확인한다.
이상이 없이 순서대로 도착하게 된 데이터 패킷이라면 수신 버퍼에 저장하고, 수신 확인 응답 TCP를 회신한다. 이후 어플리케이션이 read
를 호출했을 때 어플리케이션에 수신 버퍼에 존재하는 데이터를 건네주는 작업을 하게 된다.
정리
- LAN 어댑터는 신호를 받아들여 이를 FCS와 MAC검사 후 LAN 어댑터 버퍼에 쌓고, 인터럽트를 호출한다. 이후 CPU가 LAN 드라이버 코드를 실행하여 이를 IP 프로토콜 스택으로 보낸다.
- IP 프로토콜 스택에서는 수신 IP를 조사하고 리어셈블링과 라우팅을 진행하고, 이후 TCP 프로토콜 스택은 이에 맞는 소켓을 찾아 접속, 데이터, 종료 등 알맞은 작업을 실행한다.
웹서버 소프트웨어가 리퀘스트 메시지의 의미를 해석하여 요구에 응한다
웹서버가 클라이언트로부터 받은 리퀘스트 메시지에는 메소드라는 일종의 명령과, 데이터 출처를 나타내는 URI 라는 파일의 경로명 같은 것이 쓰여있으며, 이 내용들에 따라 웹 서버 내부의 동작이 달라진다.
웹 서버에서 공개하는 디렉토리는 디스크의 실제 디렉토리가 아니라 가상으로 만든 디렉토리이기 때문에, 파일을 읽을 때에는 가상의 디렉토리와 실제 디렉터리의 대응 관계를 조사하게 된다.
만일 URI 부분에 쓰여있는 파일명을 조사하여 이것이 .cgi
나 .php
같은 확장자라면 이것을 프로그램으로 간주하여 이에 맞는 내부 동작이 수행된다.
클라이언트로부터 오는 모든 응답에 리소스를 회신하는 것이 아니라, 클라이언트의 주소, 도메인명, 사용자명과 패스워드에 따라 동작을 수행하거나 거부하는 것이 기본 동작이 될 수 있다.
웹브라우저가 응답 메시지를 받아 화면에 표시한다
브라우저의 화면 표시 동작은 응답 메시지로 받은 데이터가 어떤 종류인지를 조사하는 것부터 시작된다.
응답 메시지의 맨 앞 부분에 존재하는 Content-Type이라는 헤더 파일의 값으로 판별하는 것이 원칙이며, 해당 값의 슬래시 앞쪽은 주 타입이고, 뒷쪽은 서브 타입이다.
이후 Content-Encoding이라는 값을 통해 데이터에 어떤 변환이나 인코딩이 이루어졌는지 알아낼 수 있다.
'공부한 이야기 > 네트워크' 카테고리의 다른 글
네트워크 패킷 맛보기 (1) | 2024.06.30 |
---|---|
1% 네트워크 V : 서버측의 LAN에는 무엇이 있는가 (0) | 2023.04.29 |
1% 네트워크 III : 케이블의 앞은 LAN 기기였다 (0) | 2023.04.29 |
1% 네트워크 II-I IP와 이더넷의 패킷 송수신 동작 (0) | 2023.04.29 |
1% 네트워크 II : TCP/IP의 데이터를 전기 신호로 만들어 보낸다 (0) | 2023.04.29 |