TCP ( Transmission Control Protocol ) network로 데이터를 전송 하는 protocol중 하나이다.
TCP 와 대표적으로 같이 비교되는 것이 UDP ( User Data Protocol ) 이 있다. 둘의 비교에서 가장 중요한 부분은 신뢰성 이다. TCP/IP 는 Client 와 Server간의 communication을 통해서 순서의 역전, 데이터 유실 등의 데이터 정확성을 보장한다. 반면 UDP는 이러한 신뢰성이 보장되지 않는다. 하지만 TCP 에 비해서 훨씬 빠른 속도를 보장하기 때문에 패킷 하나하나의 중요성 보다는 보다 빠른 전송을 목적으로 사용한다. 그 예로 비디오 스트리밍, 음원, 온라인 게임등에서 사용한다.
TCP 연결을 맺을 때는 3-ways handshake를 사용하게 되고 연결을 끊을 때는 4 ways handshake를 사용한다.
클라이언트가 서버에게 SYN 패킷을 보냄 (sequence : x)
서버가 SYN(x)을 받고, 클라이언트로 받았다는 신호인 ACK와 SYN 패킷을 보냄 (sequence : y, ACK : x + 1)
클라이언트는 서버의 응답은 ACK(x+1)와 SYN(y) 패킷을 받고, ACK(y+1)를 서버로 보냄
클라이언트는 서버에게 연결을 종료한다는 FIN 플래그를 보낸다.
서버는 FIN을 받고, 확인했다는 ACK를 클라이언트에게 보낸다. (이때 모든 데이터를 보내기 위해 CLOSE_WAIT 상태가 된다)
데이터를 모두 보냈다면, 연결이 종료되었다는 FIN 플래그를 클라이언트에게 보낸다.
클라이언트는 FIN을 받고, 확인했다는 ACK를 서버에게 보낸다. (아직 서버로부터 받지 못한 데이터가 있을 수 있으므로 TIME_WAIT을 통해 기다린다.)
서버는 ACK를 받은 이후 소켓을 닫는다 (Closed)
TIME_WAIT 시간이 끝나면 클라이언트도 닫는다 (Closed)
데이터를 송수신하다 보면 수신자입장에서 데이터의 저장용량이 가득차서 overflow가 발생하는 경우가 생길 수 있다. 이럴 때를 수신자는 송신자에게 피드백을 주어서 데이터 송신의 양을 줄여달라고 요청을 하는 방식으로 데이터 수신의 양을 줄이게 된다. 이러한 일련의 과정을 흐름제어라고 볼 수 있다.
혼잡제어란
흐름제어에는 크게 두 가지의 방법이 있는데 Stop and wait, Sliding window 방식이 있다.
단순하게 일정량의 패킷만 보내고 처리했다는 응답이 올 때까지 다음 packet을 보내지않고 기다리는 방식이다.
굉장히 원시적인 방법이고 비효율적인 방식이다. 실제로 해당 방식을 사용하지는 않고 아래 기술할 Sliding window를 사용한다.
슬라이딩 윈도우는 앞서 Stop and wait와 다르게 수신측이 감당할 수 있는 윈도우의 크기를 피드백해주기 때문에 송신측에서 이를 기준으로 송신을 하는 차이가 있다. 따라서 일일이 ACK를 기다릴 필요 없이 해당 윈도우 크기에 맞춰서 request를 보내주면 되는 것이다.
하지만 실제로 윈도우 크기를 조절하는데는 다양한 요인이 있다. 송/수신측의 혼잡도, RTT,MTU 등이 고려되어서 결정하게 된다.
Client 와 Server 가 데이터를 주고받고 있는 과정이다. Client,Server 의 window size 는 200으로 맞춰져 있는 상태이다. client 의 initial sequence number ( ISN ) 은 0인 상태이고 Server는 240인 상태로 가정한다.
Client 쪽의 바는 Rcv Buffer 의 모습이고 Server는 Sen Buffer의 모습이다. ( 처음에 이해를 못했음 )
Send Request ( Client ) : Client 의 RCV.NXT는 241로 돼어 있는 상태 (다음에 받을 byte의 위치 241 ) 140 bytes의 데이터를 보내고 해당 데이터의 Seq Num 1을 보낸다.
Receive Request, Send Combined Ack & Reply ( Server ) : Server 도 Client에게 80bytes의 데이터를 전송한다. 또한 Server의 Seq Num 241( RCV.NXT에 맞게 )을 보낸다. 서버가 받은 데이터를 잘 처리했다고 가정 하고 Ack Num = 141을 보내 다음에 보낼 데이터 byte의 위치를 보낸다.
Receive Combined Ack & Reply, Send Acknowledgement ( Client ) : Client는 추가로 보낼 데이터가 없고, Server측이 보낸 데이터를 받고 처리하여 RCV.NXT를 80 더해 321로 변경 sliding window도 그에 따라 옆으로 이동한다. 그 후 Ack Num 321을 보내 다음 데이터를 요청.
Send Part 1 of Requested File( Server ) : Server는 280bytes의 파일을 보내려고 하는데 현재남아있는 Send Buffer가 120 이기 때문에 120 만큼만 먼저 보낸다. 본인이 보낸 데이터의 최초 인덱스 Seq Num 321도 함께 이 부분이 Sliding window의 throughput을 증가시키는 핵심이라고 볼 수 있다. 응답이 오지 않았음에도 다음 요청을 한다.
Receive Part 1 of File, Send Acknowledgement ( Client ): 데이터를 받고 다음 Ack Num 441 을 보낸다. 데이터는 또한 처리 됐기 때문에 RCV.NXT=441이 되고 그만큼 윈도우를 민다. 다음 데이터를 요청 Ack Num=441
Receive Ack For Reply( Server) : 80에 대한 처리가 끝났기 때문에 Send buffer의 윈도우를 80만큼 밀고 남은 공간은 80이다. 이 때 너무 적은양의 데이터를 보내는 과정은 퍼포먼스가 좋지 않기 때문에 100 bytes아래는 보내지 않게했다고 가정 Usable이 늘어날 때까지 대기한다.
Receive Ack For Part 1 of File: 120 bytes에 대한 처리 응답이 왔고 window를 120만큼 밀어 200 의 Usable 공간이 생긴다.
Send Part 2 of File: 남은 160 bytes를 보내게 된다.
Receive Part 2 of File, Send Acknowledgement : 160에 대한 bytes를 처리하고 Rcev buffer의 윈도우를 160만큼 밀어준다. 그 후 Ack Num=601을 응답으로 보낸다.
Receive Ack For Part 2 of File: 더이상 보낼 데이터가 없음! 전송 완료.
송신측의 데이터는 지역망이나 인터넷으로 연결된 대형 네트워크를 통해 전달된다. 만약 한 라우터에 데이터가 몰릴 경우, 자신에게 온 데이터를 모두 처리할 수 없게 된다. 이런 경우 호스트들은 또 다시 재전송을 하게되고 결국 혼잡만 가중시켜 오버플로우나 데이터 손실을 발생시키게 된다. 따라서 이러한 네트워크의 혼잡을 피하기 위해 송신측에서 보내는 데이터의 전송속도를 강제로 줄이게 되는데, 이러한 작업을 혼잡제어라고 한다.
TCP Tahoe는 처음에는 Slow Start를 사용하여 자신의 윈도우 크기를 지수적으로 빠르게 증가시키다가 ssthresh를 만난 이후부터는 AIMD을 사용하여 선형적으로 윈도우 크기를 증가시킨다. 그러다가 ACK Duplicated나 Timeout이 발생하면 네트워크에 혼잡이 발생했다고 판단하고, ssthresh와 자신의 윈도우 크기를 수정하게 된다.
장애가 발생하면 무조건 윈도우 크기를 1로 만들고 다음 sshthres를 1감소시킨다. 장애가 발생하게 되면 윈도우크기가 1이되는 부분 때문에 갑작스러운 속도저하가 생길 수 있다.
TCP Reno는 TCP Tahoe 이후에 나온 정책으로, Tahoe와 마찬가지로 Slow Start로 시작하여 임계점을 넘어서면 AIMD을 사용한다. 다만, Tahoe와는 다르게 3 ACK Duplicated와 Timeout 혼잡 상황을 구분한다.
3 ACK Duplicated 가 발생하면 sshthres를 1감소시키고 현재 윈도우를 반으로 줄이게 된다. 하지만 Timeout이 발생했을 때는 sshthres에 대한 변화는 없고 현재 윈도우 크기만 반으로 줄이게 된다. 장애상황에 따라서 다른 대처를 적용한 방법.
어떤 이유에 의해서 패킷전송이 실패했을 때 어떻게 처리를 할지에 대한 제어를 오류제어라고 한다.
Go-Back-N 방식은 receiver 측에서 순서대로 받지 못한 패킷이 있다면 해당 패킷부터 다시 재전송 하는 방식이다.
수신자 입장에서 정상적으로 받지 못한 패킷이 있을 경우에 뒤에 온 패킷이 정상이라 할지라도 모두 버리고 오류가난 패킷부터 다시 가져오는 방식이다. 이와 같은 방식으로 인해서 송신자 입장에서 이전의 ack가 오지 않아도 마지막 ack만 온다면 모두 정상전송 됐다고 판단하여 cumulative ACK라고도 불린다.
GBN을 사용하게 되면 불필요하게 정상 데이터도 재전송해야하는 낭비가 있다는 단점이 있다.
GBN과 다르게 실패한 패킷에 대해서만 요청을 받기 때문에 낭비되는 재전송이 줄어든다 하지만 받는 수신자 입장에서 패킷의 순서가 달라지는 문제가 생기기 때문에 재배열을 해줘야한다. 이에 따른 추가적인 버퍼가 필요하다.
http://www.tcpipguide.com/free/t_TCPSlidingWindowDataTransferandAcknowledgementMech-5.htm