TCP는 연결지향적이며 오류제어, 흐름제어, 혼잡제어, 타이머재전송 등의 기능을 하며 연결지향이란 말은 데이터를 전송하는 측과 제이터를 전송받는 측에서 전용의 데이터 전송 선로(Session)을 만든다는 의미이다. 데이터의 신뢰도가 중요하다고 판단될 때 주로 사용된다.

TCP에서 연결지향적인 특성을 갖게 해주는 과정 및 방법이 바로 3 Way Handshake방식이다.
1. 클라이언트가 서버에게 접속을 요청하는 SYN 패킷을 보내고 SYN/ACK 응답을 기다리는 SYN_SENT 상태가 된다.
2. 서버는 Listen 상태로 포트 서비스가 가능한 상태여야 한다. (Closed: 닫힌상태) B서버는 SYN 요청을 받고 A클라이언트에게 요청을 수락한다는 ACK와 SYN flag가 설정된 패킷을 발송하고 A가 다시 ACK으로 응답하기를 기다린다. 이때 B서버는 SYN_RECEIVED 상태가 된다.
3. 클라이언트는 서버의 응답인 ACK와 SYN flag를 받고, 서버에게 ACK를 보낸다. 이후로부터는 연결이 이루어지고 이때 B서버는 ESTABLISHED 상태가 된다.


처음에 클라이언트에서 SYN 패킷을 보낼 때 Sequence Number에는 랜덤한 숫자가 담겨진다.
Sequence Number가 순차적인 숫자로 전송된다면 서버는 이전의 Connection으로부터 전송되는 패킷으로 인식할 수 있다.
위 방식을 통해 TCP는 연결지향적인 특성과 자체적으로 오류를 처리하며 순서가 뒤바뀐 패킷을 교정해주는 기능이 있어 데이터의 신뢰도가 중요하다고 판단되어질 때 쓰인다.
신뢰도 확보가 중요하거나 용량이 큰 데이터를 전달하는데 실시간일 필요가 없을 때 활용된다.
하지만 데이터의 신뢰성 보다 전송 속도가 중요시되는 경우면 어떨까? 스트리밍 서비스 같은 경우 속도가 생명이다. 만약 계속해서 버퍼링이 걸린다면 사용자는 매우 불쾌할 것이다.
앞서 말한 UDP 프로토콜은 위와 같은 과정이 없이 단순히 데이터만을 전송하므로 속도가 빠르다. 스트리밍 서비스 같은 경우 약간의 화질이나 음질의 손상이 있다해도 끊기지 않는 서비스가 중요하다. 그래서 UDP방식을 사용한다.
4 Way Handshake
세션을 종료하기 위한 절차이다.

1. 통신을 종료하고자 하는 Client가 서버에서 FIN 패킷을 보내고 자신은 FIN_WAIT_1 상태로 대기한다.
2. FIN 패킷을 받은 서버는 해당 포트를 CLOSE_WAIT으로 바꾸고 잘 받았다는 ACK를 Client에게 전하고 ACK를 받은 Client는 상태를 FIN_WAIT_2로 변경한다.
그와 동시에 Server에서는 해당 포트에 연결되어있는 Application에게 Close()를 요청한다.
3. Close() 요청을 받은 Application은 종료 프로세스를 진행시켜 최종적으로 close()가 되고 server는 FIN 패킷을 Client에게 전송 후 자신은 LAST_ACK로 상태를 바꾼다.
4. FIN_WAIT_2에서 Server가 연결을 종료했다는 신호를 기다리다가 FIN을 받으면 받았다는 ACK를 Server에 전송하고 자신은 TIME_WAIT로 상태를 바꾼다 (TIME_WAIT에서 일정 시간이 지나면 CLOSED 되게 된다.)
최종 ACK를 받은 Server는 자신의 포트도 CLOSED로 닫게 된다.
※ TIME_WAIT
만약 server에서 FIN을 전송하기 전에 전송한 패킷이 Routing 지연이나 패킷 유실로 인한 재전송 등으로 인해 FIN 패킷 보다 늦게 도착하는 상황이 발생될수도 있다.
Client에서 세션을 종료시킨 후 뒤늦게 도착하는 패킷이 있다면, 이 패킷은 Drop되고 데이터는 유실될 것이다.
이러한 현상에 대비하여 Client는 Server로부터 FIN을 수신하였다 하더라도 일정시간(default 240sec) 동안 세션을 남겨놓고 잉여패킷을 기다리는 과정을 거치게 되는데 이 과정을 TIME_WAIT 라고 한다.
또한 CLOSE_WAIT은 Application이 close()를 적절하게 처리하지 못하면 CLOSE_WAIT 상태로 계속 기다리게 되어 Socket Hang Up 에러가 발생할 수 있습니다.
※ 비정상 종료 상황
- CLOSE_WAIT 상태 : 어플리케이션에서 close()를 적절하게 처리해주지 못하면, TCP 포트는 CLOSE_WAIT 상태로 계속 기다리게 된다. 이렇게 CLOSE_WAIT 상태가 statement에 많아지게 되면, Hang이 걸려 더 이상 연결을 하지 못하는 경우가 생기기도 한다. 따라서 어플리케이션 개발시 여러 상황에 따라 close() 처리를 잘 해줘야 한다.
- FIN_WAIT_1 상태 : FIN_WAIT_1 상태라는 것은 상대방측(그림.클라이언트->서버)에 커넥션 종료 요청을 했는데 ACK를 받지 못한 상태로 기다리고 있는 것이다. 이것은 아마 서버를 찾을 수 없는 것으로, 네트워크 및 방화벽의 문제일 수 있다. FIN_WAIT_1의 상태는 일정 시간이 지나 Time Out이 되면 자동으로 닫는다.
- FIN_WAIT_2 상태 : FIN_WAIT_2 상태는 클라이언트가 서버에 종료를 요청한 후 서버에서 요청을 접수했다고 ACK를 받았지만 서버에서 종료를 완료했다는 FIN을 받지 못하고 기다리고 있는 상태이다. 이 상태는 양방의 두 번의 통신이 이루어졌기 때문에 네트워크의 문제는 아닌 것으로 판단되며 (FIN을 보내는 순간에 순단이 있어 못 받은 것일수도 있다.) 서버측에서 CLOSE를 처리하지 못하는 경우일 수 있다. FIN_WAIT_2 역시 일정 시간이 지나 Time Out이 되면 자동으로 닫는다.
- 어떠한 이유에서 FIN_WAIT_1과 FIN_WAIT_2 상태인 견결이 많이 남아있다면, 문제가 발생할 수 있다. 물론 일정 시간이 지나 Time Out이 되면 연결이 자동으로 종료되긴 하지만 이 Time Out이 길어서 많은 수의 소켓이 늘어만 난다면, 메모리 부족으로 더 이상 소켓을 오픈하지 못하는 경우가 발생한다. (이 경우는 네트워크 방화벽 또는 어플리케이션에서 close() 처리 등에 대한 문제등으로 발생할 수 있으며, 원인을 찾기가 쉽지 않다.)
출처
'CS > 네트워크' 카테고리의 다른 글
TCP 흐름제어, 오류제어, 혼잡제어 (0) | 2021.09.17 |
---|---|
OSI 7계층 (0) | 2021.09.06 |