전송 제어 프로토콜(TCP)은 웹 서비스 부터 데이터베이스 연결, FTP 전송, 텔넷 접속 등 인터넷에서 가장 핵심이 되는 전송 계층 프로토콜이다. TCP는 데이터 누락을 방지하고 전송 순서를 보장하는 연결 지향형 프로토콜이다. 연결지향이란 두 호스트가 신호를 통해 서로 상태를 확인하고 연결을 수행하고, 연결 종료 시에도 동일하게 수행한다.
호스트 A가 connect() 명령으로 호스트B에 연결하자 SYN 플래그 세그먼트를 호스트B에 전송하고 연결 상태는 SYN_SENT가 된다. SYN 플래그 세그먼트를 받은 호스트B는 SYN과 수신SYN에 대한 ACK 플래그 세그먼트를 호스트A에 송신하고 연결 상태는 SYN_RECV가 된다. 호스트B로부터 연결을 허가하는 SYN+ACK 플래그 세그먼트를 받은 호스트A는 연결이 완료된 상태인 ESTABLISHED로 바뀐다. 호스트B도 ACK를 받아 ESTABLISHED 상태가 되면 accept()되어 데이터 송수신 상태가 준비 완료된다. 이 과정에서 3번의 세그먼트 흐름이 발생해 Three way handshake라고 한다. 이후에는 애플리케이션에서 send(). recv() 명령으로 데이터 송수신이 이뤄진다.
연결을 닫는 과정도 연결하는 과정과 비슷하다. 호스트A가 작업이 완료되어 close()명령을 호출하면 호스트B에 FIN 플래그 세그먼트를 보내고, 상태는 FIN_WAIT_1이 된다. 호스트B는 FIN 플래그 세그먼트를 받으면 내부적으로 close()명령이 호출되기 기다리는 CLOSE_WAIT 상태가 되고 FIN에 대한 응답 ACK를 보낸다. 호스트A가 ACK를 받으면 상태는 FIN_WAIT_2로 바뀐다. 이후 일정 시간 동안 호스트B의 FIN 플래그 세그먼트를 받지 못하면 상태는 TIME_WAIT로 변한다. 이후 호스트B에서 close()가 호출되면 그제서야 FIN플래그 세그먼트가 호스트A로 전달하고 상태는 LAST_ACK가 된다. 호스트 A는 최종적으로 FIN 플래그 세그먼트를 받았으므로 네트워크 연결을 닫고, FIN에 대한 응답으로 ACK 플래그 세그먼트를 호스트B로 보낸다. 호스트 B는 ACK 수신 후 네트워크 연결을 닫는다.
TCP는 연결을 끊을때 한쪽에서만 close()를 호출한다고 해서 연결이 끊어지지 않는다. 상대방 역시 명시적으로 close()를 해야 연결이 끊어진다. 한쪽만 연결을 닫은 상태에서는 상대방이 계속 send()를 수행할 수 있는 상태가 열려있게 되어 데이터 수신이 가능하다. 그래서 TCP의 close를 half close라고도 한다.
윈도우, 유닉스, 리눅스 모두 netstate -n 명령어를 사용하면 네트워크 연결 상태를 볼 수 있다. 여기를 통해 누가 네트워크를 연결하고 누가 네트워크를 끊는지 정보를 볼 수 있다.
TCP 전송보장
전송보장 알고리즘
TCP 의 가장 큰 특징은 전송 보장이다. 데이터 전송이 보장되는 프로토콜이기 때문에 인터넷에서 널리 사용되는 것이다. TCP는 IP 기반에서 동작하는데 IP는 전송 보장형 프로토콜이 아니고, 네트워크 패킷 자체는 네트워크 환경과 라우팅에 따라 순서가 뒤바뀌거나 누락이 발생할 수 있다. TCP가 IP 기반위에서 데이터 전송을 보장하는 방법은 SEQ(Sequence), ACK(Acknowledge)로 수신 데이터 순서(offset)을 확인하고 누락/지연 패킷에 대한 재전송 알고리즘을 제공해 IP를 보완하기 때문이다. 그래서 애플리케이션에서 수신된 데이터를 읽어 들일때는 정확히 송신 순서에 맞게 데이터 누락없이 처리된다.
SEQ와 ACK는 서로 상대방에게 내가 보내는 데이터 순서정보(SEQ)와 내가 정상적으로 받은 데이터 정보(ACK)를 보내는 것이다.
- SEQ : 현 연결에서 현재까지 송신한 데이터 총 크기(바이트단위)이자 순서번호(Offset). 수신 측에서는 상대방이 지금까지 나에게 보낸 데이터 총량을 알 수 있다. 그리고 SEQ번호는 전체 데이터상의 위치번호와 같으므로 데이터 순서를 맞추는데 사용된다.
- ACK : 현 연결에서 현재까지 누락 없이 수신한 데이터 총 크기(바이트단위)이자 다음 수신을 원하는 SEQ 번호, 상대방이 누락 없이 받은 데이터 총량을 알 수 있으며, 누락 발생 시 재전송해야 하는 SEQ 번호를 알 수 있다. 재전송은 상대방이 계속(마지막)에 보내오는 ACK 번호와 일치하는 SEQ 번호의 데이터를 전송하면 된다.
송신측에서 볼때, 데이터 세그먼트를 계속 보내는데 그에 대한 ACK가 증가하지 않고 계속 동일한 ACK가 오는것을 중복 ACK라고 한다. 중복 ACK가 일정횟수(리눅스, AIX는 3회)만큼 발생하면 송신측은 세그먼트가 중간에 누락된 것으로 판단하고 해당 ACK번호와 일치하는 SEQ의 데이터 세그먼트를 재전송한다. 중복 ACK에 의한 재전송은 타임아웃에 의한 재전송에 비해 재전송을 판단하는 시간이 짧아 재전송이 빨리 이뤄지므로 빠른 재전송(Fast Retransmission)이라고 한다.
재전송 발생 여부는 네트워크 소요시간에서 RTT 못지 않게 중요한 성능요소로서 체크해야 한다. 재전송이 빈번하게 발생한다는 것은 장비 불량이나 네트워크 이상 또는 장비 설정 이상을 유추할 수 있는 단서이기도 하므로 무시하고 넘겨서는 안된다.
선별적인 ACK
TCP에서 ACK 번호는 현재까지 데이터 누락없이 받은 마지막 SEQ 번호에 대한 ACK이자 재전송시 받기를 원하는 SEQ 번호이다. 이처럼 ACK 번호가 누적 개념으로 동작할때 송신자 입장에서는 재전송 필요 시점에 대상 세그먼트를 1개만 식별할 수 있다. 그래서 세그먼트 손실이 많은 네트워크에서는 전송 속도를 더욱 저하시키는 요소가 뇓다. 이를 보와하기 위해 나온것이 선별적인 ACK(SACK; Selective Acknowledgment)이다.
8세그먼트를 전송했는데 4,7번 세그먼트가 전송 과정에서 누락되었을때 기존방식은 1,2,3번 세그먼트에 대해서는 각각 ACK를 받지만 5,8번 세그먼트에 대해서는 계쏙 3번에 대한 ACK를 받는다. 재전송 인지 시점에 4번 세그먼트를 보내면 6번에 대한 ACK를 받고 다시 7번의 누락을 인지하고 7번을 보내면 8번에 대한 ACK를 받아 통신이 놔룐된다. 먼저 누락된 세그먼트를 보내고 그에 대한 ACK를 받아야 그다음 누락된 세그먼트를 인지하는 방식이다.
그러나 선별적인 ACK는 각 세그먼트에 대한 ACK를 보내는 방식으로 1,2,3,5,6,8번 세그먼트에 대해 ACK가 전송되어 송신자가 누락된 4번 세그먼트를 재전송해서 ACK를 받지 않아도 7번이 누락된 것을 인지하고 재전송할 수 있다. 그래서 재전송을 인지하고 속도가 빨라 재전송이 많이 발생하는 환경에서는 우수한 성능을 발휘할 수 있다. 하지만 세그먼트마다 ACK를 보냄으로써 네트워크 사용량을 증가시키는 효과가 있다.
선택적 ACK 사용은 TCP 옵션으로 연결을 맺을 때 송신자가 수신자에게 SYN 세그먼트 내 TCP 옵션으로 SACK Permitted(Type 4)를 보냄으로써 상대방에게 SACK를 처리할 수 있음을 알린다. 그럼 수신자는 데이터 세그먼트에 대한 ACK를 보낼때 TCP 옵션으로 SACK(Type 5)임을 송신자에게 알린다.
수신자가 SACK 옵션에 추가로 최대 3개까지 데이터 블록 정보를 전송한다. 데이터 블록 정보는 세그먼트 누락 없이 연속으로 받은 데이터 블록으로, 블록들 사이가 누락이 발생한 구간이라고 할 수 있다. 한 블록 정보는 32비트의 unsigned int 형식으로 블록의 시작과 끝을 의미하는 SEQ 번호다. 시작은 해당 블록의 왼쪽 SEQ 번호이고, 끝은 해당 블록의 오른쪽 끝 SEQ 번호 다음에 위치하는 SEQ번호이다. 따라서 두 번호를 빼면 해당 블록에서 누락없이 연속해서 받은 바이트 단위 데이터양이 된다. 한 SACK 옵션에는 이러한 연속된 블록 정보를 3개까지 보낼 수 있다.
출처: 권문수, [실무로 배우는 시스템 성능 최적화], 위키북스, 2016, 730~746p
'네트워크' 카테고리의 다른 글
6. UDP & 기타 프로토콜 (0) | 2021.10.16 |
---|---|
5. TCP(Transmission Control Protocol)_전송제어 (0) | 2021.10.09 |
3. IP 프로토콜 네트워크 체크 명령 (0) | 2021.08.08 |
2. IP(Internet Protocol) (0) | 2021.08.01 |
1. 네트워크 기초 (0) | 2021.07.27 |
댓글