웹 애플리케이션에는 서로 통신하는 서버와 클라이언트로 구별되는 두 가지 프로그램이 있는데, 사용자의 호스트에서 실행되는 브라우저 프로그램
과 웹 서버 호스트에서 실행되는 웹 서버 프로그램
이다.
따라서 새로운 애플리케이션을 개발할 때는 여러 종단 시스템에서 실행되는 소프트웨어를 작성해야 한다. 이러한 소프트웨어는 C, 자바 혹은 파이썬으로 작성된다.
애플리케이션 구조는 애플리케이션 개발자가 설계하며, 애플리케이션 구조를 선택할 때 애플리케이션 개발자는 현대 네트워크 애플리케이션에서 사용되는 두 가지 잘 알려진 구조 중 하나로 작성할 것이다.
클라이언트-서버 구조
에서 항상 동작하고 있는 호스트를 서버
라고 부르는데 서버와의 서비스는 클라이언트
라는 다른 호스트들로부터 서비스 요청을 받는다. 클라이언트-서버 구조
에서 클라이언트는 서로 직접적으로 통신하지 않는다는 점에 주목할 필요가 있다. 웹 애플리케이션에서는 2개의 브라우저가 직접적으로 통신하지 않는다는 것을 의미한다.
또한 서버가 고정 IP 주소러는 잘 알려진 주소를 갖는다는 점도 특징이다. 서버는 항상 동작하고 있으므로 클라이언트는 서버 주소로 패킷을 보내서 언제든지 서버에 연결할 수 있다.
때로 클라이언트-서버 애플리케이션에서 하나의 서버 호스트가 자신의 클라이언트로부터 오는 모든 요청에 다 응답하는 것은 불가능하다. 인기 있는 새로운 웹사이트가 하나의 서버로만 요청을 처리한다면 이에 맞춰 서버가 신속하고 제대로 작동하지 못할 수 있다. 이러한 이유로 많은 수의 호스트를 갖춘 데이터 센터
가 강력한 가상의 서버를 생성하는 역할로 사용된다.
클라이언트와 서버 프로세스
웹에서 브라우저는 클라이언트 프로세스이고, 웹 서버는 서버 프로세스다. 두 프로세스 간의 통신 세션에서 통신을 초기화하는 프로세스를 클라이언트
라 하고, 세션을 시작하기 위해 접속을 기다리는 프로세스를 서버
라고 한다.
프로세스와 컴퓨터 네트워크 사이의 인터페이스
하나의 프로세스로부터 다른 프로세스로 보내는 메시지는 네트워크를 통해 움직인다. 프로세스는 소캣
을 통해 네트워크로 메시지를 보내고 받는다.
그림에서 보듯이, 소켓은 호스트의 애플리케이션 계층과 트랜스포트 계층 간의 인터페이스다. 또한 소켓은 네트워크 애플리케이션이 인터넷에 만든 프로그래밍 이넡페이스이므로, 애플리케이션과 네트워크 사이의 API
라고도 한다. 애플리케이션 개발자는 소켓의 애플리케이션 계층에 대한 모든 통제권은 갖지만, 소켓의 트랜스포트 계층에 대한 통제권은 거의 갖지 못한다.
프로세스 주소 배정
한 호스트상에서 수행되고 있는 프로세스가 패킷을 다른 호스트에서 수행되고 있는 프로세스로 패킷을 보내기 위해서는 수신 프로세스가 주소를 갖고 있을 필요가 있다. 수신 프로세스를 식별하기 위해서는 두 가지 정보가 명시되어야 한다.
호스트의 주소
목적지 호스트 내의 수신 프로세스를 명시하는 식별자
인터넷에서 호스트는 IP 주소로 식별된다. 또한 송신 호스트는 수신 호스트에서 수행되고 있는 수신 프로세스도 식별해야 한다. 이 정보는 일반적으로 한 호스트가 많은 네트워크 애플리케이션을 수행할 수 있기 때문이다. 목적지 포트 번호
가 이 목적을 위해 사용된다. 인기 있는 애플리케이션은 특정한 포트 번호가 할당된다. 웹 서버는 포트 번호 80번으로 할당된다.
송신 측의 애플리케이션은 소켓을 통해 메시지를 보낸다. 소켓의 반대편 트랜스포트 프로토콜은 네트워크를 통해 메시지를 수신 프로세스의 소켓으로 이동시킬 책임이 있다.
인터넷을 포함해서 많은 네트워크는 하나 이상의 트랜스포트 프로토콜을 제공하는데 애플리케이션을 개발할 때는 사용 가능한 트랜스포트 프로토콜 중에서 하나를 선택해야 한다. 아마 애플리케이션의 요구에 가장 적합한 서비스를 제공하는 프로토콜을 선택할 것이다.
인터넷은 일반적으로 애플리케이션에게 2개의 전송 프로토콜, 즉 UDP
와 TCP
를 제공한다. 새로운 애플리케이션을 만들 때 가장 먼저 결정해야 하는 것 중 하나는 TCP와 UDP 중 어느 것을 사용할 것인가이다. 두 프로토콜은 애플리케이션에게 각기 다른 서비스 모델을 제공하기 때문이다.
TCP 서비스
TCP 서비스 모델은 연결지향형 서비스와 신회적인 데이터 전송 서비스를 포함한다. 또한 TCP는 혼잡 제어 방식, 즉 인터넷의 전체 성능 향상을 위한 서비스를 포함한다.
UDP 서비스
UDP는 최소의 서비스 모델을 가진 간단한 전송 프로토콜이다. UDP는 비연결형이므로 두 프로세스가 통신을 하기 전에 핸드셰이킹을 하지 않는다. UDP는 비신뢰적인 데이터 전송 서비스를 제공한다.
애플리케이션 계층 프로토콜은 다른 종단 시스템에서 실행되는 애플리케이션의 프로세스가 서로 메시지를 보내는 방법을 정의한다.
네트워크 애플리케이션
과 애플리케이션 계층 프로토콜
을 구별하는 것은 중요하다. 애플리케이션 계층 프로토콜은 네트워크 애플리케이션의 한 요소일 뿐이다. 예를 들어 웹은 사용자가 필요에 따라 웹 서버로부터 문서를 얻게 해주는 네트워크 애플리케이션이다. 웹 애플리케이션은 HTML, 웹 브라우저, 웹 서버, 애플리케이션 계층 프로토콜을 포함하는 여러 요소들로 구성된다. 웹 애플리케이션 계층 프로토콜, HTTP는 브라우저와 웹 서버 사이에서 교환되는 메시지의 포맷과 순서를 정의한다.
웹의 애플리케이션 계층 프로토콜인 HRRP는 웹의 중심이다. 클라이언트 프로그램과 서버 프로그램은 서로 HTTP 메시지를 교환하여 통신한다.
웹 페이지는 객체들로 구성된다. 객체는 단순히 단일 URL로 지정할 수 있는 하나의 파일이다. 대부분의 웹페이지는 기본 HTML 파일과 여러 개의 참조 객체로 구성된다.
HTTP는 웹 클라이언트가 웹 서버에게 웹 페이지를 어떻게 요청하는지와 서버가 클라이언트로 어떻게 웹 페이지를 전송하는지를 정의한다. 사용자가 웹 페이지를 요청할 때, 브라우저는 페이지 내부의 객체에 대한 HTTP 요청 메시지를 서버에게 보낸다. 서버는 요청을 수신하고 객체를 포함하는 HTTP 메시지로 응답한다.
HTTP는 TCP를 전송 프로토콜로 사용한다. HTTP 클라이언트는 먼저 서버에 TCP 연결을 시작한다. 일단 연결이 이루어지면, 브라우저와 서버 프로세스는 그들의 소켓 인터페이스를 통해 TCP로 접속한다. 클라이언트 측에서 보면 소켓 인터페이스는 클라이언트 프로세스와 TCP 연결 사이에서의 출입구다. 반면 서버 측에서 보면 소켓 인터페이스는 서버 프로세스와 TCP 연결 사이에서의 출입구다. 클라이언트는 HTTP 요청 메시지를 소켓 인터페이스로 보내고 소켓 인터페이스로부터 HTTP 응답 메시지를 받는다. 마찬가지로, HTTP 서버는 소켓 인터페이스로부터 요청 메시지를 받고 응답 메시지를 소켓 인터페이스로 보낸다.
HTTP 명세서는 메시지 포맷을 정의한다. 두가지 HTTP 메시지, 즉 요청 메시지
와 응답 메시지
가 있다.
GET / somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr
HTTP 요청 메시지의 첫 줄은 요청 라인
이라 부르고, 이후의 줄들은 헤더 라인
이라고 부른다. 요청 라인은 3개의 필드, 즉 방식 필드
, URL 필드
, HTTP 버전 필드
를 갖는다. 헤더 라인은 다양한 정보가 들어있다.
이 응답 메시지는 앞서 살펴본 예제의 요청 메시지에 대한 응답이다.
HTTP/1.1 200 OK
Connection: close
Date: Tue, 18 Jul 2023 12:11:03 GMT
Server: Apache/2.2.3 (centOS)
Content-Length: 6821
Content-Type: text/html
이 응답 메시지는 3개의 섹션, 즉 초기 상태 라인, 5개의 헤더 라인, 개체 몸체로 이루어졌다. 모든 것이 양호함(OK)을 나타낸다.
HTTP 서버는 상태를 유지하지 않는다. 이것은 서버 설계를 간편화하게 하고 동시에 수천 개의 TCP 연결을 다룰 수 있는 고성능의 웹 서버를 개발하게 해주었다. 그러나 서버가 사용자 접속을 제한하거나 사용자에 따라 콘텐츠를 제공하기 원하므로 웹사이트가 사용자를 확인하는 것이 바람직할 때가 있다. 이 목적으로 HTTP는 쿠키
를 사용한다.
위 그림을 예를 들어 쉽게 설명해보자. 나는 이베이 사이트에 방문한 적이 있다고 가정을 해본다. 그리고 아마존 사이트는 처음 방문한다. 아마존 웹 서버에 요청이 들어올 때 그 서버는 유일한 식별번호를 만들고 이 식별번호로 인덱싱되는 백엔드 데이터베이스 안에 엔트리를 만든다. 그런 후 아마존 웹 서버는 내 브라우저에 응답하는데, 이 HTTP 응답에 식변번호를 담고 있는 Set-cookie: 헤더가 포함된다.
내 브라우저가 HTTP 응답 메시지를 받았을 때 그 Set-cookie: 헤더를 볼 수 있다. 그런 다음 브라우저는 관리하는 특정한 쿠키 파일에 그 라인을 덧붙이게 된다. 이 라인은 서버의 호스트 이름과 Set-cookie: 헤더와 식별번호를 포함한다. 내가 웹 페이지를 요청할 때 내 브라우저는 쿠키 파일을 참조하고 이 사이트에 대한 식별번호를 발췌하고, HTTP 요청에 식별번호를 포함하는 쿠키 헤더 파일을 넣는다. 이러한 방식은 나의 아마존 사이트에서의 활동을 추적할 수 있다. 비록 내 이름을 아마존 웹사이트가 알 필요는 없지만 1678 사용자가 어느 페이지를, 어떤 순서로, 몇시에 방문했는지 정확히 알 수 있다. 예를 들어 '쇼핑 카드' 서비스를 제공하기 위해 이런 쿠키를 사용한다. 따라서 세션이 끝날 때 총괄하여 지불할 수 있는 것이다.
만약 내가 아마존 사이트를 일주일 후에 다시 접속하면 내 브라우저는 Cookie: 1678 을 헤더 라인에 넣어 요청 메시지를 보낸다. 아마존은 또한 내 과가에 아마존에서 방문한 웹 페이지에 기초하여 제품을 추천한다. 만약 내가 내 정보를 등록했다면 아마존은 이 정보를 데이터베이스에 추가하고, 그것에 의해 내 식별번호를 이름과 연관시킨다. 다음에는 내 정보를 재입력할 필요가 없어진다.
하지만 이런 방식은 사생활 침해로 이어질 수 있는 논쟁거리이다.
웹 캐시는 기점 웹 서버를 대신하여 HTTP 요구를 충족시키는 네트워크 개체다. 웹 캐시는 자체의 저장 디스크를 갖고 있어 최근 호출된 객체의 사본을 저장 및 보존한다. 브라우저는 사용자의 모든 HTTP 요구가 웹 캐시에 가장 먼저 보내지도록 구성될 수 있다. 일단 브라우저가 설정되면 객체에 대한 각각의 브라우저 요청은 웹 캐시에 가장 먼저 보내진다.
캐시는 서버이면서 클라이언트라는 점을 유의해야 한다. 브라우저로부터 요구를 받고 응답을 보내는 것이 서버이고, 출처 서버에게 요구를 보내거나 응답을 받는 것이 클라이언트이다.
일반적인 네트워크 애플리케이션은 2개의 종단 시스템에 존재하는 클라이언트 프로그램과 서버 프로그램으로 구성된다. 이 두 프로그램을 수행하면 클라이언트와 서버 프로세스가 생성되고, 두 프로세스가 소캣으로부터 읽고, 소캣에 쓰기를 통해 서로 통신한다. 네트워크 애플리케이션을 생성할 때 개발자의 주 업무는 클라이언트와 서버 프로그램 모두에 대한 코드를 작성하는 것이다.
TCP는 연결지향 프로토콜로, 클라이언트와 서버가 서로에게 데이터를 보내기 전에 먼저 TCP 연결을 설정할 필요가 있음을 의미한다. TCP 연결의 한쪽은 클라이어느 소켓에 연결되고 다른 쪽은 서버 소켓에 연결된다. TCP 연결을 생성할 때 클라이언트 소켓 주소와 서버 소켓 주소를 연결과 연관시킨다. TCP 연결이 설정된 후, 한쪽에서 다른 쪽으로 데이터를 보내려면 소켓을 통해 데이터를 TCP 연결로 보내면 된다.
좀더 구체적으로 살펴보면 클라이언트는 서버로의 접속을 먼저 시도한다. 서버는 클라이언트의 초기 접속에 응대할 수 있도록 준비하고 있어야 한다. 프로세스/소켓에 대한 집과 출입문 비유를 이용해서 '출입문을 두드리는 것'으로 표현한다.
서버 프로세스가 수행되면 클라이언트 프로세스는 서버로의 TCP 연결을 시도한다. 이는 클라이언트 프로그램에서 TCP 소켓을 생성함으로써 가능하다. 클라이언트 TCP 소켓을 생성할 때 서버에 있는 환영 소켓의 주소, 즉 서버의 IP 주소와 소켓의 포트번호를 명시한다. 소켓을 생성한 후 클라이언트는 세 방향 핸드셰이크를 하고 서버와 TCP 연결을 설정한다.
세 방향 핸드셰이크 동안 클라이언트 프로세스는 서버 프로세스의 출입문을 두드린다. 서버가 노크를 들으면 서버는 새로운 출입문, 즉 해당 클라이언트에게 지정되는 새로운 소켓을 생성한다. 연결을 시도하는 클라이언트에게 지정된 새로 생성된 소켓을 connectionSocket
이라고 한다.
애플리케이션 관점에서 볼 때 클라이언트의 소켓과 서버의 연결 소켓은 파이프에 의해 직접 연결된다. 클라이언트 프로세스는 자신의 소켓으로 임의의 바이트로 보낼 수 있으며 보낸 순서대로 서버 프로세스가 바이트를 수신하도록 TCP가 보장한다. 따라서 TCP는 클라이언트와 서버 프로세스 간에 신뢰적 서비스를 제공한다.