[네트워크] TCP

정한별·2024년 2월 5일

네트워크

목록 보기
4/13

(항상 잘못된 정보가 포함되어 있을수 있습니다)
(잘못된 정보가 있다면 댓글로 피드백 부탁드리겠습니다)

TCP란

TCP는 세계 통신표준으로 개발된 OSI 모형에서 4번째 계층인 전송 계층(Transport Layer)에서 사용하는 규약이다.
TCP는 데이터를 신뢰성 있게 주고받기 위한 프로토콜이다.
그래서 몇가지 특징을 가지고 있다

  • 신뢰성 있는 전송
    TCP는 데이터의 신뢰성을 보장하기 위해 여러 메커니즘을 사용한다.
    순서보장과 재전송 메커니즘, handshake 등등..
  • 흐름 및 혼잡 제어
    흐름을 제어해 수신자가 송신자에게 데이터를 받을 수 있는 속도로 데이터를 전송하도록 보장하고, 네트워크의 혼잡을 방지하고 전송 속도를 제어하여 네트워크 성능을 최적화하기도 한다.
  • 양방향 통신
    양쪽 방향으로 동시에 데이터를 주고받을 수 있다.

이번 포스팅에서는 Handshake에 대해서 알아보자

handshake

TCP는 연결된 상태에서 데이터를 주고받는 연결 지향적 프로토콜이다.
이러한 열결을 설정하기 위해서 3 Way handshake 과정을 거치고,
종료하기 위해 4 Way handshake 과정을 거친다.
이 과정을 통해 각 호스트는 연결을 설정 및 종료하자는 의사를 표시하고 확인한다. 연결이 되었음을 확신해야 서로 데이터를 주고 받는다.
이러한 과정들은 중간에서 공격을 시도하는 해커가 연결을 가로채거나, 연결을 종료하는것을 방지하는 도움을 준다. 이는 안전하고 신뢰성있게 데이터를 수신할수 있다는 뜻이다.

3 way handshake

복잡한 해설을 보기전에 요약글을 먼저 보도록 하자.

클라이언트: 여보세요 서버 잘 들리세요?
서버: 네 클라이언트 잘들립니다. 그쪽도 잘 들리세요?
클라이언트: 네 잘 들립니다.

연결을 설정하기 위한 과정

  • 클라이언트 -> 서버
    접속을 요청하는 SYN 패킷을 보냄
    (클라 = SYN_SENT 상태)
  • 서버 -> 클라이언트
    서버가 요청을 수락하고 클라이언트가 보내온 SYN안에 담긴 SEQ + 1 한 값(ACK)과 또 하나의 SYN 패킷을 보냄
    (서버 = SYN_RECEIVED 상태)
  • 클라이언트 -> 서버
    서버가 보내온 SYN안에 담긴 SEQ + 1 한 값(ACK)이 담긴 패킷을 보냄 그럼 연결 성공
    (클라 = ESTABLISHED 상태)
  • 서버
    ACK 확인 연결 시작
    (서버 = ESTABLISHED 상태)
  • SYN - (SYnchronize sequence Number) 연결을 확인을 위하여 쓰는 난수 SEQ가 담긴 패킷
    (처음 클라가 보내는 SEQ를 ISN이라고도 함)
  • ACK - (ACKnowledgements) SYN안에 SEQ에 + 1 한 값

ISN을 0부터 시작하지않고 난수를 사용하는 이유
연결을 사용하는 포트는 유한 범위 내에서 사용하고 시간이 지남에 따라 재사용된다.
따라서 두 통신 호스트가 과거에 사용된 포트 번호를 사용하는 가능성이 존재한다.
서버 측에서는 패킷의 SYN을 보고 패킷을 구분하게 되는데 난수가 아닌 순처적인 Number가 전송된다면 이전의 연결로부터 오는 패킷으로 인식할 수 있다.
이런 문제가 발생할 가능성을 줄이기 위해서 난수로 ISN을 설정한다.

이를 예시로 한번 보면

  • 클라이언트가 서버로 12345라는 SEQ가 담긴 SYN패킷 전송
  • 서버가 클라이언트로 12345에 + 1 한 12346 ACK와 98765라는 SEQ가 담긴 SYN 패킷을 전송
  • 클라이언트가 12346인지 확인하고 98765라는 값에 + 1 한 98766 ACK를 서버로 전송

4 way handshake

복잡한 해설을 보기전에 요약글을 먼저 보도록 하자.

A: 여보세요? 끊어도 되나요?
B: 네 여보세요 잠시만요.
B: 네 이제 끊어도 됩니다.
A: 네 그럼 끊겠습니다.

연결을 해제하기 위한 과정


연결 종료의 경우 클라이언트 to 서버, 서버 to 클라이언트 모두 가능

  • 송신자 -> 수신자
    연결종료를 위한 FIN 패킷 전송
    (송신자: FIN_WAIT1 상태)
  • 수신자 -> 송신자
    송신자가 보내온 FIN 패킷안에 SEQ값 + 1 한값(ACK)을 보낸다.
    하지만 이것이 곧 연결을 종료한다는 의미가 아니다.
    왜냐면 종료를 먼저 원한게 송신자니까 수신자는 아직 보낼 데이터가 남아 있을수도 있다.
    (수신자: CLOSE_WAIT 상태)
    (송신자: FIN_WAIT2 상태)
  • 수신자 -> 송신자
    이제 수신자도 연결종료해도 된다는것을 나타내기 위해 FIN 패킷을 전송한다
    (수신자: LAST_ACK 상태)
  • 송신자 -> 수신자
    수신자가 보내온 FIN 패킷 안에 SEQ값 + 1 한값(ACK)를 보낸다.
    (송신자: TIME-WAIT 상태)
    여기서 TIME-WAIT 상태가 좀 중요한데
    수신자가 FIN 패킷을 보내기전에 아직 보낼데이터가 남아 있을수도 있다했다.
    근데 이 수신자가 보낼데이터가 보내지고 FIN 패킷을 보냈는데 FIN 패킷이 먼저 도착한다고 바로 종료하면 이 보낼데이터는 받을수가 없다.
    그렇기때문에 이런 상황을 방지하기 위해 FIN 패킷을 보내더라도
    TIME-WAIT 연결을 열어서 일정시간동안 데이터를 받게끔 하는 것이다.
  • 수신자
    ACK 확인후 연결 종료
    (수신자: CLOSED)
  • 송신자
    TIME WAIT 시간이 끝나면 완전히 연결을 종료
    (수신자: CLOSED)

FIN = 연결을 종료시킬 때 사용되며 더이상 전송할 데이터가 없음을 나타내는 플래그
3 Way와 마찬가지로 난수 SEQ 값을 가지고 있음

이를 예시로 한번 보면

  • 클라이언트가 종료를 원해 서버로 FIN(SEQ: 12345) 전송
  • 서버는 클라로 ACK(12346) 전송
  • 서버가 남은데이터를 전송후 자기도 종료를 원해 FIN(SEQ: 98765) 전송
  • 클라이언트는 서버로 ACK(98766) 전송
  • 서버는 ACK를 받고 연결종료
  • 클라이언트는 혹시 못받은 데이터를 받기위해 TIME_WAIT 상태
  • TIME_WAIT시간이 지나 종료되면 연결 종료

이러한 handshake 과정을 통해 신뢰성있는 데이터를 주고 받을수 있게 된다.

TCP와 HTTP의 차이

TCP통신은 OSI 4계층에서 동작한다.

TCP통신은 3-way-handshake라는 과정을 거치고 연결이 이루어진다.
그리고 연결을 종료할때는 4-way-handshake를 거치게 된다.
이를 연결지향적 이라고 얘기하고, 연결을 종료하지 않으면 계속해서 연결을 유지하며 통신할수 있다.

또한, TCP통신에서는 소켓을 이용한 연결방식을 사용한다.
그로인해, 양방향 통신이 가능하게 되는데 양방향 통신이란, 클라이언트단과 서버단이 서로 연결되어 있을때 서로 요청을 보내고 응답을 받는 통신을 할 수 있게 해주는 것이다.
또한, 클라이언트단과 서버단의 연결이 끊어지지않고 계속 연결을 유지해주어 실시간 소통이 가능하다.

위와같이 소켓을 이용한 연결은 TCP 프로토콜 기반으로 맺어진 연결이며, 소켓통신이라고도 부른다.

TCP = 연결지향, 양방향

HTTP는 OSI 7계층에서 동작한다.
즉 HTTP는 TCP보다 상위 계층에 있는데
쉽게 말하면 TCP를 기반으로한 프로토콜이다.

하지만 HTTP는 비연결성을 가지는 통신 프로토콜이다.
또한 양방향 통신을 하지않는 단방향 통신 프로토콜이다.
클라이언트에서 요청을하고 서버가 응답하면 바로 연결을 끊어버리는,
그리고 클라이언트가 요청하고, 서버는 응답하는 단방향 구조인 것이다.

HTTP = 비연결성, 단방향

TCP = 연결지향, 양방향
HTTP = 비연결성, 단방향

쉽게 말해 HTTP가 TCP라는 수단을 이용해서 자기 원하는대로 사용하는것이다.

아주 완벽한 예가 될수는 없지만
내가 도끼를 사용해서 요리를 할 수도있고, 나무를 자를수도 있을것이다.
HTTP는 TCP를 사용해서 원하는 통신을 진행하는것이다.

HTTP는 전송할 데이터를 어떤 형태로 주고받을지를 규칙으로 만든 프로토콜이고
이것을 주고받는 방식은 TCP 방식을 이용하는것이다.

초기 HTTP를 만들때는 웹 관련 기능에 대한 지원과 같이 웹용으로 특별히 설계된 이에 최적화된 프로토콜을 만들고 싶었고
그에 대한 전송방법으로 신뢰성높은 장점이 있는 전송방법인 TCP를 이용했고 전달 방법에 대해서는 웹에 특화되게 한 HTTP 프로토콜만든게 아닐까? 싶다.

HTTP 3.0

HTTP 3.0부터는 TCP통신을 이용하지 않고 UDP 통신을 이용한다.
그 이유가 무엇일까?
TCP 통신은 구조상 한계가 너무 명확하다.

  • 너무큰 헤더
    TCP 헤더에는 목적지 및 출발지 포트, 순서 번호, 확인 응답 번호, 플래그 등 다양한 정보가 들어간다. 이 정보들은 신뢰성 있는 통신을 제공하기 위해 필요하지만, 아주 작은 데이터를 주고 받을땐 데이터들보다 헤더가 더큰 배보다 배꼽이 더큰 상황이 생기기도 한다.
  • 3 Way Handshake로 인한 지연되는 통신과정
  • 정확한 순서로 처리돼야 하는 패킷
    TCP를 사용한 통신에서 패킷은 무조건 정확한 순서대로 처리되어야 한다.
    HOLB는 패킷이 전송되는 순서대로 도착하지 않을 때 발생하는 현상을 말하는데
    이런경우 다음에 전송되어야 할 패킷들도 함께 대기해야 한다.. 따라서 하나의 패킷이 지연되면 그 뒤의 모든 패킷도 지연될 수 있어 효율성이 떨어지게 되는것이다.

이러한 구조적 한계 때문에
HTTP 3.0부턴 UDP를 통신 방법으로 이용한다.

UDP는 TCP보다 신뢰성이 없는 대신 빠르다

라고 했다.
근데 사실 UDP가 신뢰성이 없는건 아무런 기능이 없어서다.

이게 무슨 소리냐면 하얀 도화지마냥 기능이 없기때문에 신뢰성이 없는것이다.
데이터 전송을 제외한 그 어떤 기능도 정의되어 있지 않은 프로토콜이다.

그렇기 때문에 HTTP를 개발하는 개발자들이 여기에
예를들어 이정도면 신뢰성이 생길만큼 충분해 라고 하는 기능들만
넣어서 커스터마이징 할수 있다는 뜻이다.

모든게 이미 다 들어가서 수정하기 힘든 TCP보다
백지상태에서 그려나가는 방식을 택한것이다.

그래서 UDP 위에 QUIC라는 프로토콜을 덮어서 만든것이 바로
HTTP 3.0이다.

QUIC는 나중에 한번 제대로 된 포스팅으로 알아보자.

profile
iOS Developer

0개의 댓글