네트워크

TCP Error Control

teo_99 2024. 4. 11. 00:01

앞서 TCP의 흐름 제어, 혼잡 제어를 살펴봤다. 이외에도 TCP는 오류 제어라는 기법을 사용하는데, 이번 글에서 어떻게 TCP가 오류에 대한 제어를 수행하는지 살펴본다.

 

우선 오류 제어가 무엇인지, 왜 필요한지 당위성부터 알 필요가 있다. TCP는 Survivalability가 중요한 프로토콜이다. 신뢰성 있는 통신을 지향하며, 가능한 효율적으로 작동한다.

 

통신은 오류가 발생할 수 있다. 잡음이 발생해 패킷이 손상되거나, 순서가 잘못되었거나, 버려지는 등 항상 의도한대로 동작할 순 없다. 따라서 이러한 오류가 발생했을 때 적절히 대처하는 방법이 필요한데, 그것이 오류 제어다.

 

TCP 오류 제어는 여러 기법들을 사용해서 진행된다. 크게는 총 3가지 기법을 사용한다고 말할 수도 있는데, 체크섬, ACK, 재전송이다. 이제 각각에 대해서 알아보도록 하겠다.

 

Checksum

TCP 헤더에는 Checksum 필드가 존재한다. 이를 통해 패킷이 손상되었는지 여부를 판단할 수 있다. 

http://www.ktword.co.kr/test/view/view.php?no=1796

 

체크섬은 16비트의 값을 가진 필드인데, 위 그림과 같이 여러 요소들을 복합적으로 고려해 체크섬이 계산된다. 체크섬이란, 간단하게 에러를 검출할 수 있는 일종의 간단한 메커니즘이라고 이해하면 된다.

 

그림을 보면 알겠지만, TCP 체크섬은 TCP 헤더 부분만 고려하는 것은 아니다. 가상 헤더라고 표현된 부분과, 실제 데이터, 그리고 Padding까지 고려해 체크섬이 계산된다.

 

TCP 헤더, 데이터 부분만 고려하는게 아니라 가상 헤더까지 고려하는 이유는 목적지라는 개념이 IP 주소와 포트 번호까지 함께 고려되어야 하기 때문이다. 그렇기 때문에 IP 헤더의 일부분을 가상 헤더로 활용한다고 한다.

 

가상 헤더(Pseudo Header)

가상 헤더는 사실 TCP를 만들면서 '가상 헤더가 필요하겠군!' 해서 바로 넣어진게 아니라, 어떠한 역사적 배경과 관련이 있다. 

 

사실 TCP가 처음 등장했을 때에는 TCP/IP 처럼 구분되어 등장한게 아니라, IP와 결합된 형태로 등장했다. 즉, TCP가 라우팅과 트래픽 자체를 모두 통제하는 상황이었다. IP라는 개념이 TCP 속에 녹아들어 있던 상태라고 봐도 무방하다. 그리고 다음은 초기 TCP의 헤더를 그림으로 표현한 것이다.

Early TCP Header

현재 우리가 알고 있는 TCP의 헤더와는 조금 다르다. Destination TCP Address, Source TCP Address 부분이 현재의 IP에 해당하는, 즉 라우팅을 수행하는 부분이다. 다만 시간이 지나고, 네트워크가 더욱 복잡해지면서 라우팅만을 위한 계층이 필요하게 되었고, TCP/IP로의 전환도 이루어진다. 즉, 우리가 알고 있는 TCP 헤더의 모습으로 변화한 것이다.

 

Recent TCP Header

 

이 과정에서 TCP의 가상 헤더도 생겨났다. 초기 TCP는 'End-to-End' 프로토콜로 정의되었다. 하지만 TCP/IP 모델로 변화하면서 TCP 헤더만으로는 'End-to-End' 프로토콜임을 보장할 수 없다는 것이다.

 

그렇기 때문에 TCP/IP 모델에서는 가상 헤더를 활용하여 IP 부분의 주소까지 고려하게 된다. 이를 통해 TCP 자체적으로도 엔드포인트 주소가 손상되지 않았음을 보장할 수 있게 된다. 즉, TCP의 개념 정의를 면밀히 따르다보니 생긴 결과다.

 

아무튼, TCP는 이러한 가상 헤더를 포함해서 체크섬을 생성한다. 송신 측에서는 가상 헤더를 포함한 체크섬을 계산해 전송하고, 수신 측에서도 마찬가지로 가상 헤더를 생성해 체크섬이 올바른 값인지를 확인한다. 체크섬을 구하는 방법은 의외로 간단한데, 단순히 값들을 모두 더한 뒤 1의 보수를 취하는 형식이다.

 

ACK 및 재전송(Retransmission)

체크섬은 오류가 발생했다고 판단되면 패킷을 폐기하는 방식이다. 이외에도 TCP는 재전송 기반의 오류 제어 기법도 가지고 있다. 이는 흐름 제어와 어느정도 겹치는 내용이 많은데, 이전 내용을 간단히 복기한 뒤 추가적인 내용을 설명하도록 하겠다.

 

TCP는 ACK 기반으로 동작한다는 사실은 알 것이다. TCP는 재전송 타이머를 가지고 있어서, 타이머가 울리기 전에 ACK가 도착하지 않으면 재전송을 진행한다. 혹은 타이머가 울리기 전이라도 ACK가 n번 (통상 3번) 이상 발생하면 오류라고 판단하고 곧바로 재전송한다는 사실도 혼잡 제어에서 배웠다. (Fast Retransmission)

 

이외에도 TCP는 이전에 설명하지 않았던 오류 제어를 위한 추가적인 기능들을 가지고 있는데, 하나씩 알아보도록 하자.

 

NACK or NAK

TCP에는 ACK 응답만 있는 것이 아니다. Negative ACK라고 해서, '부정 확인응답'이라는 방법도 존재한다. 직관적으로 이해할 수 있듯이, 정상적으로 수신되지 않았음을 알리는 메세지이다. 

https://ianfinlayson.net/class/cpsc414/notes/09-transport2

 

다만 NACK는 실제로는 잘 사용되지 않고, 위성 통신과 같은 특수한 상황에 주로 사용되는 편이다. 일반적인 경우라면 ACK 응답 혹은 재전송 타이머를 통해 오류 제어가 충분히 가능하기 때문에 굳이 추가적인 비용을 들여서 NACK를 보내지는 않는 것 같다. 반면 '오류가 발생한 이유' 등을 통지해야만 하는 critical한 상황이라면 NACK가 사용될 수도 있다.

 

Go Back N ARQ

이외에도 ARQ의 한 종류인 Go Back N ARQ 기법을 사용하여 오류 제어를 수행하기도 한다. 

 

Go Back N ARQ 방식에서 ACK 응답이 타이머가 울리기 전에 도착하지 않았거나, NACK 응답이 도착했다면 오류라고 판단하고 재전송을 진행한다. 다만, 여기서 중요한 점은 오류가 발생한 패킷 지점부터 전부 전송한다는 것이다.

 

https://www.geeksforgeeks.org/sliding-window-protocol-set-2-receiver-side/

 

그림을 보면 알 수 있듯이, 2번 패킷에 대해 Packet Loss가 발생한다면 수신측은 이후에 받는 모든 패킷을 폐기한다. 또한 송신 측에서는 타이머가 울리기 전에 ACK 응답을 받지 못했으므로, 2번 패킷부터 모든 패킷을 재전송한다. 이처럼 오류가 발생하면 되돌아가서 다시 전송하고, 이것이 이름이 'Go Back' N ARQ라고 지어진 이유이기도 하다. 

 

다만 '오류가 발생했다면 해당 부분만 재전송하면 되지 않을까?' 라는 생각이 들 수도 있다. 그리고 해당 방식을 구현한게 Selective Repeat ARQ 방식이다. 

 

Selective Repeat ARQ

이름에서부터 알 수 있듯이, Selective Repeat는 선택적으로 '어떠한 부분을 받지 못했음'이라고 알리는 프로토콜이다. 그림으로 우선 살펴보면 다음과 같다. 

https://www.youtube.com/watch?app=desktop&v=zBBlV_iQ9YM

 

재전송 타임아웃이 발생했을 때, 2번 패킷에 대해서는 ACK 응답을 받지 못했으므로 '선택적으로' 2번 패킷만 재전송한다. 만약 Go Back N ARQ 프로토콜을 사용했더라면 2번 패킷을 포함해 이후의 모든 패킷(3, 4, 5)를 모두 재전송했을 것이다.

 

Go back N ARQ 방식의 경우, 수신받는 패킷은 순서를 항상 보장받았다. 즉, ACK 응답을 보내는 순서가 항상 역행하지 않는다는 것이다. 가령 4번 ACK를 보냈다면, 1번부터 3번 패킷은 수신이 잘 되었음을 보장할 수 있다. 

 

다만 Selective Repeat ARQ 방식의 경우라면, ACK 응답이 중간에 비어도 큰 문제가 되지 않는다. 송신측에서 타이머가 종료되면 재전송을 할 것이기 때문이다.

 

하지만 이는 다른 말로는, 연산량이 크다는 것을 의미하기도 한다. 순서와 상관없이 도착한 패킷들에 대해 항상 재정렬을 해야 하기 때문이다. 따라서 Go Back N ARQ 프로토콜에 비해 계산량이 크다.

 

현재의 TCP는 Go Back N ARQ가 아닌, Selective Repeat 방식을 기본으로 사용한다. 다만 이는 운영체제의 구현에 따라 달라질 수 있으나 최근에는 컴퓨팅 능력의 향상으로 재정렬로 인한 오버헤드를 그렇게 크게 따지지 않는 것 같다. 관련해서 전공 교수님께 여쭤본 결과, 요즘에는 기기나 네트워크의 상황보다는 '전송하고자 하는 패킷의 특성'에 따라 결정되는 경우가 많다고 한다.

마치며

이상으로 TCP의 흐름, 오류, 혼잡제어를 모두 살펴봤다. 생각보다 쉽지 않은 내용이었고, 추후 추가적인 내용을 학습하게 된다면 글을 보강하도록 하겠다.

 

참고 자료

http://www.ktword.co.kr/test/view/view.php?nav=2&no=1299&sh=TCP+%EC%98%A4%EB%A5%98%EC%A0%9C%EC%96%B4

http://www.ktword.co.kr/test/view/view.php?no=1796

https://www.baeldung.com/cs/pseudo-header-tcp

https://evan-moon.github.io/2019/11/22/tcp-flow-control-error-control/

https://ddongwon.tistory.com/81

https://www.javatpoint.com/go-back-n-arq

https://en.wikipedia.org/wiki/Sliding_window_protocol#Examples

https://www.geeksforgeeks.org/sliding-window-protocol-set-2-receiver-side/