시작하며
HTTP(HyperText Transfer Protocol) 통신은 클라이언트와 서버 간 데이터를 주고 받기 위한 프로토콜이다. 다시 말하면, HTTP 통신 자체는 어떤 형식의 데이터를 보낼지 미리 정의해 놓는 방식일 뿐이다. 따라서 클라이언트와 서버간 HTTP 통신이 일어나기 위해서는 데이터를 주고 받기 위한 여러 기술이 필요하다. 이번 글에서는 HTTP 통신이 일어나기 위해 내부적으로 어떤 일이 일어나는지를 정리해본다.
IP 레이어
IP 레이어란 무엇인가?
먼저 클라이언트와 서버를 생각해보자. 클라이언트와 서버는 컴퓨터일 뿐이며, 데이터를 요청하는 쪽이 클라이언트 데이터를 보내는 쪽이 서버가 된다. 따라서 이 둘간의 통신을 위해서는, 두 컴퓨터가 연결되기 위한 주소값이 필요하다. 이러한 역할을 IP(Internet Protocol) 레이어에서 한다.
IP 레이어는 인터넷에서 데이터를 전송하기 위한 프로토콜로, 네트워크 상에서 각 기기를 식별하는데 사용하는 주소 체계이다. IP 주소를 사용해 특정 호스트로 데이터를 보낼 수 있다. 예를 들어 192.xxx.xxx.xxx 라는 IP 주소를 가진 호스트가 있다고 했을 때, 이 호스트로 데이터를 보내기 위해서는 192.xxx.xxx.xxx 주소로 데이터를 보내면 된다.
IP 주소와 포트
하지만, 192.xxx.xxx.xxx 라는 IP 주소만 사용해 데이터를 보내면 문제가 생긴다. 192.xxx.xxx.xxx 주소는 호스트의 주소이기 때문에 그 주소를 사용하는 여러 컴퓨터와 서비스가 있을 수 있기 때문이다. 이를 해결하기 위해 특정 서비스로 데이터를 보내기 위해 '포트'라는 것을 추가로 사용하면 된다.
예를 들어 80번 포트에서는 A 서비스를 위한 서버가 구동되고 있고, 8080번 포트에서는 B 서비스를 위한 서버가 구동되고 있다면, A 서비스의 서버로 데이터를 요청할 때는 http://192.xxx.xxx.xxx:8080:80 으로 요청을 하면 되며, B 서비스의 서버로 데이터를 요청할 때는 http://192.xxx.xxx.xxx:8080 으로 요청을 보내면 된다.
IP 레이어만 사용하는 것의 한계
IP 레이어에서는 특정한 목적지로 패킷을 전송한다. 하지만, 네트워크 상황에 따라 패킷이 사라지거나 손실될 수 있다. 이 때문에 IP 레이어만 사용해 패킷을 보내는 것은 신뢰성이 없다고 한다. 이러한 신뢰성 문제를 해결하기 위해 TCP 레이어가 등장한다.
TCP 레이어
TCP 레이어와 소켓 통신
보낸 패킷이 손실되는 것을 방지하고, 클라이언트와 서버간 신뢰성 있는 통신을 구축하기 위해 TCP 연결을 사용할 수 있다. 우리가 흔히 아는 소켓이 이 TCP 연결에서 주요한 역할을 한다. TCP 연결을 위해서는 다음의 과정을 거친다.
1. 먼저 서버의 소켓에 클라이언트의 소켓을 연결하려면, 서버의 소켓은 만들어져 있어야 한다. 서버에서 소켓을 만들고, 80포트에 소켓을 묶고, 소켓이 다른 소켓으로부터 요청을 받을 수 있는 상태로 만든다.
2. 클라이언트에서도 소켓을 만들고 서버의 IP 주소와 포트를 사용해 소켓에 연결을 요청(SYN)한다.
3. 서버의 소켓은 클라이언트의 소켓에 연결이 성공적으로 이뤄졌다는 응답(SYN-ACK)을 보내고, 요청을 읽기 시작한다.
4. 클라이언트는 서버의 연결 완료 응답에 대한 확인을 위해 연결 확인(ACK) 패킷을 보낸다.
소켓을 통한 HTTP 통신
이렇게 소켓 통신이 구축 완료되면, [그림7]과 같이 소켓을 사용해 HTTP 요청을 전송할 수 있으며, 마찬가지로 소켓을 통해 응답을 받을 수 있다.
TCP가 신뢰성을 보장하는 방법
TCP에서 전송되는 패킷은 IP 패킷이다. IP 패킷은 손실될 수 있지만, TCP통신은 일부 패킷이 손실되더라도 안전하게 모든 데이터가 전송될 수 있도록 여러 장치를 둔다. TCP는 특정한 데이터를 통째로 전송하는 것이 아니라, 매우 작은 단위로 나눠서 패킷으로 만들어 전송하며, 헤더에 각 작게 잘려진 패킷이 어떤 순서로 조합돼야 하는지에 대한 정보를 포함한다. 또한 TCP는 수신하는 소켓에서 패킷을 올바르게 수신했을을 확인하기 위해 확인 응답(ACK)를 사용해, 만약 특정한 데이터를 받지 못했다면, 해당 패킷을 재전송함으로써 데이터가 손실되는 것을 방지한다. 이를 통해 신뢰성 있는 데이터 송수신을 할 수 있다.