OSI 7계층은 네트워크에서 일어나는 통신 과정을 7단계로 나눈 것 입니다. 각 단계별로 여러가지 프로토콜이 존재하고 각 단계별 역할이 구분되어 있습니다. TCP/IP는 미국 국방부에서 정의한 네트워크 통신 표준 모델로 OSI 7계층을 조금 더 간단하게 표현했습니다.
한국에 살고 있는 내가 미국에 살고 있는 친구에게 편지를 보내려고 하는 일련의 과정들이 컴퓨터끼리 이루어지는 네트워크이고 이를 추상화 시킨게 계층 구조입니다. 상위 단계에서 하위 단계로 내려갈수록 더욱 구체적인 추상화가 이루어지기 때문에 응용 계층부터 물리 계층까지 알아가면 네트워크를 조금 더 쉽게 이해할 수 있습니다.
결론적으로 우리는 클라이언트 프로세스와 서버 프로세스 간의 통신(의사소통)을 하고 싶습니다. 운영체제는 같은 컴퓨터 내의 다른 프로세스끼리 통신을 하기 위해서 파이프와 같은 인터페이스(IPC)를 제공하는것 처럼 클라이언트와 서버를 연결하기 위한 인터페이스로 socket을 제공합니다.
socket을 이용하여 의사소통을 하기 위해서는 적어도 어떤 컴퓨터에 어떤 소켓(프로세스)인지 알아야 합니다. 따라서 소켓을 어드레싱 하는게 필요한데 이 역할을 하는 것이 IP, Port입니다. 여기서 IP는 어떤 컴퓨터인지 Port는 이 컴퓨터에서 어떤 프로세스의 소켓인지를 알려주는 주소역할을 하게 됩니다.
우리가 네이버를 사용하기 위해서는 IP와 Port를 입력하여 연결을 해야하지만 편의를 위해 www.naver.com을 쓰고 있습니다. 이 주소를 IP로 변환하는 역할을 DNS가 해주고 있습니다. 여기서 모든 웹서버(네이버, 구글 등)는 80번 포트를 사용하고 있는데 만약 웹서버마다 포트가 다르다면 DNS가 Port까지 찾아야 하기 때문에 웹서버의 포트는 동일한 포트를 사용하고 있습니다. 따라서 Port를 생략하면 기본으로 80을 찾아가게 되고, www.naver.com:80
을 해도 네이버로 접속이 가능합니다.
네트워크의 상위 계층은 하위 계층의 기능을 사용할 수 있습니다. Application 계층은 하위 계층인 Transport계층에서 제공하는 서비스를 받게 됩니다. 따라서 Transport에서 어떤 서비스, 기능을 제공해주는지가 중요합니다.
Data integrity : 전송된 데이터가 유실되지 않고 전송되었으면 함
Timing : 전송된 데이터가 원하는 시간안에 도착했으면 함
Throughput : 전송된 데이터의 처리량이 좋았으면 함
Security : 전송된 데이터의 보안이 좋았으면 함
Application 계층에서 바라는(?) Transport 계층의 서비스는 위와 같습니다. 하지만 현재 Transport 계층에서는 Data integrity의 서비스만을 제공해주고 있습니다. 따라서 보완과 같은 기능은 Application 계층에서 직접 구현하여 사용합니다.
hypertext란 중간에 링크들이 포함되어 있는 텍스트를 의미합니다. 결국 HTTP는 이런 텍스트를 전송하는 프로토콜이며 웹 서버가 사용하는 프로토콜입니다.
client : 브라우저를 통해 서버에게 HTTP request(요청)
server : 요청된 내용을 기반으로 적절한 파일을 찾아 HTTP response(응답)
HTTP의 특징
HTTP는 Application 계층이기 때문에 당연히 Transport 계층의 서비스를 사용합니다. 웹 서버는 특히 TCP를 사용하게 됩니다. 그렇기 때문에 클라이언트와 서버와 통신하기 전에 TCP connection이 먼저 생성이 되어야 합니다.
또한 HTTP는 stateless 합니다. HTTP는 단순히 요청이 들어왔을때 해당하는 파일을 찾아 응답하면 끝인 프로토콜입니다. 따라서 상대방에 대한 어떠한 상태도 기억하지 않는게 특징입니다.
HTTP는 TCP를 사용하는 방식에 따라 non-persistent와 persistent 방식으로 나누어집니다. non-persistent는 요청과 응답이 끝나면 TCP connection을 끊는 방식이고 persistent 이 연결을 유지하는 방식입니다.
예를 들어, 클라이언트가 home.index
라는 파일을 요청한다면 서버는 해당 파일을 찾아 응답해 줍니다. 이때 non-persistent는 TCP 연결을 끊게 되고 그 후 해당 파일의 내용을 파싱하다 보니 그 안에 ref
로 다른 사진이나 그림을 불러와야 할때 다시 TCP 연결을 하고 필요한 파일을 요청하게 됩니다. 반면에 persistent 방식은 처음 TCP 연결을 하고 모든 요청이 끝나면 TCP 연결을 끊는 방식으로 동작하기 때문에 현재는 persistent 방식을 기본적으로 사용하고 있습니다.
200 : OK
301 : Moved Permanently (리다이렉트 문제)
400 : Bad request (잘못된 문법으로 인하여 서버가 요청하여 이해할 수 없음)
404 : Not Found (요청받은 리소스를 찾을 수 없음)
505 : HTTP version not supported (서버에서 지원되지 않는 HTTP 버전을 클라이언트가 요청)
HTTP의 특징 중 stateless가 있었습니다. 서로의 상태를 기억하지 않는게 때로는 필요한데 HTTP에서는 그 기능을 구현하기 위해 cookies를 사용합니다.
클라이언트가 특정 서버와 통신을 위해 HTTP 요청을 하게 되면 cookie file안에 서버에 대한 cookie(번호)가 없으면 일반적인 HTTP 요청을 하게 됩니다. 서버는 새로 들어온 요청에 대해 쿠키를 생성하고 서버 데이터베이스에 정보를 저장 후 응답에 set-cookies를 담아서 보내줍니다. 이후에 클라이언트는 cookie 번호를 담은 요청을 보내게 되는데 중간에 브라우져를 종료하여도 정해진 만료 시간 동안은 클라이언트에 cookie가 저장됩니다.
cookie의 단점은 헤더에 정보를 추가해야 하기 때문에 비용이 증가하고 중요한 정보를 cookie에 저장하였을때 cookie가 유출된다면 보안에 대한 문제가 발생할 수 있습니다.
cookie의 단점을 보완하기 위해 나온 기술입니다. HTTP Session id를 식별자로 구별하여 데이터를 사용자의 브라우저에 cookie형태로 저장하는 것이 아니라 서버 데이터베이스에 저장하는 방식입니다. 클라이언트에는 HTTP Session id를 cookie의 형태로 메모리에 가지고 있기 때문에 브라우져가 종료되면 사라지게 됩니다.
session의 단점은 서버의 저장 장치가 부족하면 적합하지 않습니다.
현재 웹 서버의 통신은 클라이언트와 서버 사이에 프록시(proxy)라는 서버가 존재합니다. 프록시 서버는 서버의 내용을 캐시로 가지고 있습니다. 만약 클라이언트가 같은 요청을 반복한다면 서버까지 통신할 필요 없이 프록시 서버에 저장된 내용을 곧바로 읽어올 수 있습니다. 또한 클라이언트는 직접 서버에 접근하는 것이 아니라 프록시 서버를 경유하기 때문에 서버는 IP 노출이 적어져 보안상으로 사용하기도 합니다. 비슷한 이유로 클라이언트의 IP 또한 바뀌기 때문에 우회의 목적으로 사용되기도 합니다.
하지만 캐시의 역할을 하는 프록시 서버는 원본 데이터가 변하면 캐싱된 데이터는 변하지 않는다는 문제를 가지고 있습니다. 이 문제를 해결하기 위해 Conditional GET을 사용합니다.
Conditional GET은 클라이언트(프록시 서버)가 if-modified-since: <date>
라는 필드를 사용하여 특정 날짜 이후로 데이터가 수정되었는지 확인 목적으로 서버에 요청을 하게 되고 수정되지 않았다면 서버는 304
응답을 하게 됩니다. 만약 수정이 되었다면 데이터를 담아서 응답하고 프록시 서버는 해당 데이터를 캐싱하게 됩니다.
HTTP와 달리 메일을 받는 사람이 24시간 상주하는 것이 아니기 때문에 다른 프로토콜을 사용합니다.
사용자가 메일을 전송하면 SMTP 형식으로 내가 사용하는 메일 서버(naver mail)를 통해 전송된다.
메일 서버(naver mail)는 받는 메일 서버(daum mail)에게 SMTP 형식으로 데이터를 전송한다.
전통적으로 메일 서버(daum mail)은 IMAP의 형식으로 클라이언트에게 메일을 보냈지만 현재는 브라우져를 통해 메일을 사용하므로 HTTP를 사용하는 추세이다.
서버와 클라이언트 간에 파일을 전송하기 위한 프로토콜입니다.
김철수의 번호는 012-345-6789로 저장된 전화번호부 처럼 DNS는 호스트 네임의 실제 ip주소를 찾아주는 역할을 합니다.
DNS 시스템은 위의 그림처럼 이루어진 데이터를 분산화 및 계층화 하여 이루어집니다.
root name server : 원하는 IP주소를 찾기 위해 전 세계의 분산화 되어 같은 정보를 가지고 있는 서버
TLD(top-level domain) DNS server : com
, net
, org
등으로 나눠져 있는 서버
authoritative DNS server : 네트워크를 구성하는 조직은 같은 네트워크 안에 있는 호스트네임과 ip정보를 저장해야 하고 그 역할을 하는 서버
Local DNS name server : 로컬에 매핑 정보를 캐싱해 두는 서버
예시) 내가 naver.com에 요청을 보내는 상황
Local DNS name server에 naver.com 정보가 있는지 요청
없다면 Local DNS name server가 root name server에 정보 요청
root name server는 ip주소는 모르지만 TLD DNS server 정보 응답
Local DNS name server는 TLD DNS server에 정보 요청
TLD DNS server는 ip 주소는 모르지만 authoritative DNS server(naver)의 정보 응답
Local DNS name server는 authoritative DNS server에 정보 요청
authoritative DNS server는 ip주소 응답
DNS는 UDP 방식을 사용합니다. 네트워크 개요에서 UDP는 데이터 손실이 일어날 수 있다고 했습니다. DNS가 주고 받는 데이터는 매우 작은 크기를 가지고 있기 때문에 그만큼 데이터 손실이 일어날 확률이 적습니다. 혹여나 데이터 손실이 일어나더라도 다시 요청하면 되고 더 나아가 DNS는 단순히 HTTP를 하기 위한 준비 단계이기 때문에 TCP 통신을 통해 너무 많은 시간이 걸리게 된는 것을 방지하기 때문입니다.
클라이언트와 서버간의 통신을 위해 운영체제가 제공하는 어떠한 인터페이스를 이용하여 통신을 해야하며 이것을 소켓(socket)이라고 했습니다. 상위 계층은 하위 계층의 서비스를 이용할 수 밖에 없기 때문에 socket도 TCP socket과 UDP socket으로 나누어 집니다.
서버의 소켓 API
서버는 socket()
을 통해 소켓을 생성
bind()
는 특정 포트에 소켓을 연결
listen()
소켓을 듣고 있는 상태(서버)로 만듬
accept()
모든 준비가 완료된 상태로 만듬
클라이언트가 요청이 오기 전까지 blocking
클라이언트 소켓 API
클라이언트 소켓 생성
클라이언트는 특정 포트랑 연결할 필요가 없이 아무 포트를 사용하면 되므로 bind()
사용 안함
특정 포트에 고정시키고 싶다면 사용해도 됨
서버측 소켓과 연결
연결이 완료되면 write()
, read()
를 사용하여 서버에게 데이터를 보내거나 서버로 부터 데이터를 읽음
모든 요청이 끝났다면 close()
를 통해 소켓은 해제하여 다른 프로세스가 사용할 수 있도록함
UDP의 경우 TCP보다 훨씬 간단하게 구성할 수 있다.