TCP는 연결형 프로토콜이다. TCP프로토콜을 사용하면 송신측과 수신측의 가상의 연결을 설정해 데이터를 교환하고 연결을 해제한다. 송신측은 다중화, 수신측은 역다중화를 수행한다. 그리고 TCP 서비스는 양방향 전송을 수행하고 전송할 때 전송할 데이터와 수신한 데이터에 대한 확인 응답을 함께 보내는 피기배킹(piggybacking)을 한다. TCP 프로토콜의 특징을 하나하나 살펴보자.
TCP 프로토콜의 특징
- 신뢰성있는 데이터 통신
- 연결형(Connection-Oriented)
- 흐름제어(Flow Control)
- 혼잡제어(Congestion Control)
- 스트림 통신
신뢰성 있는 데이터 통신
응용 계층에는 보내는 프로세스와 받는 프로세스가 존재한다. 만약 신뢰성 있는 프로토콜을 사용하게 되면 받는 프로세스는 전송계층에서 보내는 데이터가 에러없이 보낸 순서대로 도착한다고 신뢰할 수 있다.
이상적인 개념으로는 만약 전송 계층의 하위 레벨에서 에러가 발생하지 않고 신뢰성있게 전송될 수 있다면, 전송 계층에서는 에러를 체크할 필요도 없고, 전송이 잘 되었는지도 확인할 필요가 없다. TCP가 할 일이 줄어든다는 것이다.
그러나 필연적으로 전송계층의 하위 계층에서는 유무선의 링크를 거쳐오면서 에러가 발생하게 된다. 전송계층에서는 unreliable한 하위 레벨의 데이터 통신을 체크해서 재전송이나 에러복구를 통해 에러를 해결한 후 그것을 응용 계층의 수신자에게 전달하게 된다. 이러한 방식으로 신뢰성있는 연결을 보장한다.
에러가 발생할 수 있는 형태는 크게 두가지가 있다.
- 비트 에러(Bit Error)
전송 시 매체의 불량으로 데이터가 왜곡,손실될 수 있다. 비트오류는 segment에 담긴 checksum 정보를 확인하여 발생 여부를 알 수 있다. segment에 에러가 없으면 수신자는 송신자에게 ACK(Acknowledgement message)를 보낸다. 그럼 송신자는 데이터가 에러없이 잘 도착했다는 것을 알 수 있다. 만약 에러가 발생했다면 수신자는 송신자에게 에러가 발생했다는 NAK를 보낸다. 송신자가 NAK를 받으면 에러가 발생했다는 것을 알 수 있다.
- 패킷 손실(Packet Loss)
송신자가 데이터를 송신하는 도중에 데이터가 손실될 수도 있고, 수신자가 보내는 ACK가 손실될 수도 있다. 보낸 패킷이 손실되었는지 알 수 있는 방법이 없고, 응답을 무한정 기다리게 될 수도 있다. 이러한 문제를 해결하기 위해서 패킷에 대하여 Timer를 설정하여 일정 시간동안 응답이 돌아오지 않으면(timeout) 송신자가 패킷을 재전송하게 된다.
타이머의 길이를 너무 짧게 하면 ACK가 도착하기도 전에 데이터를 재전송하는 경우가 발생한다. 즉, 불필요한 재전송이 발생할 수 있어 네트워크 자원을 낭비하는 경우가 발생한다. 타이머의 길이를 너무 길게 잡으면 패킷이 분실됐을 경우 너무 오래 기다리게 되므로 전송 속도가 낮아진다. 따라서 적절한 타이머 길이를 설정하는 것이 매우 중요하다. 타임 아웃 시간을 설정할 때에는 sender와 reciever 간의 왕복 시간을 잘 고려해서 설정해야 한다.
패킷의 순서가 섞여서 도착하거나, ACK가 손실되어 송신자가 패킷을 재전송하였을 때 수신자에게 패킷이 중복되어 전송된다면 받은 패킷이 같은 패킷인지 다른 패킷인지 구분하기 위해서 각 패킷마다 일련번호를 둔다. 패킷의 일련번호를 통해 순서에 맞는 ordered delivery를 제공하고, 데이터의 중복도 방지할 수 있다.
패킷의 재전송 방식 (ARQ(Automatic Repeat Request))
stop-and-wait
송신자가 한 번에 하나의 segment를 전송하고 그에 대한 ack를 받을 때 까지 기다리는 방식이다. 수신자의 응답을 받고 나면 전송을 다시 재개한다. 만약 timeout이 될 때 까지 ACK가 오지 않는다면 패킷을 재전송한다. 수신자가 패킷을 받아서 ACK를 보냈는데 ACK가 손실된 것이라면, 수신자는 재전송된 패킷이 중복된 패킷이므로 재전송된 패킷을 버리고 ACK만 다시 재전송 한다.
stop-and-wait 방식은 ACK를 받을 때 까지는 다시 전송을 하지 않는다. 그러면 네트워크의 링크의 활용도가 높아도 사용률이 매우 낮아진다. 높은 효율의 네트워크 자원을 낭비하는 비효율적인 작업이라고 할 수 있다. 따라서 stop-and-wait 방식은 사용하지 않고, 한 번에 여러 개의 패킷을 전송하는 pipelined 방식을 사용한다.
Window
pipelined 방식을 사용하려면 윈도우가 정의되어야 한다. 윈도우는 ACK를 받지 않아도 한 번에 보낼 수 있는 데이터 사이즈를 의미한다. window size는 한번에 보낼 수 있는 패킷의 갯수이다. 윈도우 사이즈는 정해져 있지 않고 시간에 따라 변할 수 있다. sliding window라고도 한다. 윈도우 사이즈가 크면 한번에 보낼 수 있는 패킷이 많아지므로 throughput이 높아진다. 그러나 너무 높아지면 시스템에 부담이 된다. 윈도우사이즈가 너무 낮아도 한번에 보낼 수 있는 패킷이 적어 전송 속도가 줄어들고 비효율적이므로 윈도우사이즈는 시스템이 효율적으로 조절하게 된다.
pipelined 방식도 두가지로 나뉜다.
Go-back-N
Go-Back-N 방식은 한 번에 여러 개의 패킷을 전송하고 오류 패킷을 발견하면 오류 패킷부터 모두 재전송을 하는 방식이다. 그렇기 때문에 수신자는 받은 데이터에 대한 누적 ACK를 전송하게 된다. 그리고 타이머도 가장 오래전에 보낸 패킷에 대한 타이머 하나만 설정한다.
위 그림에서 패킷2가 전송 도중 손실되었다. 그러면 수신자는 패킷2를 받지 못했으니 뒤에 오는 패킷들을 모두 무시하고 패킷1이 도착했을 때의 누적아크를 계속해서 재전송한다. 어차피 뒤에 패킷들은 재전송 받을 것이므로 모두 버릴 수 있는 것이다. 패킷2에 대한 타임아웃이 발생하면 패킷2부터 다시 재전송된다.
예를 들어 packet2가 제대로 전송이 되었는데 그에 대한 ACK가 손실되어 도착하지 않았다면 Packet3가 도착했을 때 수신측애서 보낸 누적 ACK는 packet2가 잘 도착했다는 의미를 포함한다. 누적 ACK는 도착한 패킷에 대한 정보를 기억하는 역할을 하므로 항상 가장 마지막 순서의 패킷에 대한 누적 ACK를 전송한다. 그것이 Go-back-N 방식의 장점이다.
반면에 윈도우 사이즈가 큰데 앞 순서의 패킷이 손실되었다면 그만큼 그 뒷 순서의 패킷을 재전송해야 하므로 처리할 데이터가 많아진다는 단점이 있다.
Selective repeat
Selective repeat는 한 번에 여러 개의 패킷을 전송하고 만약 오류 패킷을 발견하면 오류 패킷만 재전송 하는 방식이다. 이 방식은 각 패킷에 대해 개별적인 ACK를 반송하게 된다. 또한 각각의 패킷은 각각의 타이머를 가진다. 만약 한 패킷에 대한 ACK가 안오면 ACK가 오지 않은 패킷만 재전송한다. 그래서 아래 윈도우 그림을 보면 앞에 있는 패킷의 ACK가 도착하지 않아도 뒤에 있는 패킷의 ACK가 먼저 도착할 수 있는 것이다.
수신자의 윈도우를 보면, 앞의 패킷이 아직 도착하지 않았는데 뒤의 패킷이 먼저 수신될 수 있다. TCP는 in-order delivery로 순서가 맞춰져야만 응용 계층으로 올려보낼 수 있다. 따라서 앞순서의 패킷이 도착할 때 까지 버퍼에서 기다려야 하고, 앞순서의 패킷이 도착하면 순서를 맞추어 응용 계층으로 올려보내게 된다.
Selective Repeat 방식은 전송중인 패킷의 갯수를 항상 윈도우 사이즈와 동일하게 유지할 수 있다. 만약 위의 경우처럼 pk2가 손실되었다면 pk2에 대한 타임아웃이 발생하였을 때 pk2만 다시 재전송하면 된다. pk2가 도착하지 않았기 때문에 뒤에 순서인 3,4,5 번 패킷은 버퍼에 저장되고, 패킷2가 재전송이 잘 되면 순서를 맞춰서 응용계층에 전달한다.
Selective Repeat방식에서는 일련번호의 크기에 따라 적절한 윈도우 사이즈를 설정하지 않으면 문제가 발생할 수 있다. 여기서 패킷의 일련번호는 segment 헤드에 들어가는 필드이다. 따라서 일련번호의 크기에는 제약이 있다. 위의 그림처럼 일련 번호를 0~3으로 사용한다면 3번까지 사용한 후에 다시 0반이 시작된다. 이 상황에 윈도우 사이즈가 3이라고 가정해보자. 송신자가 패킷 3개를 동시에 보내고 데이터가 문제 없이 잘 전달되면 수신측의 윈도우는 다음으로 넘어가게 된다. 그런데 그에 대한 ACK가 손실되었다고 하면 송신측은 처음 보냈던 패킷을 재전송하게 된다. 수신측의 윈도우사이즈 안에는 3,0,1 패킷이 들어올 순서인데, 재전송되는 패킷0과 패킷1이 이미 전송되었던 패킷이라고 판단하지 않고 다음에 전송받아야 할 패킷이라고 판단하게 되는 문제가 발생한다. 이러한 문제를 해결하기 위해서 윈도우 사이즈는 일련번호 범위 크기의 절반 이하로 설정하는 것이 적절하다.
Selective Repeat 방식은 개별 ACK를 사용하므로 각각의 패킷에 대한 전송을 관리할 수 있다는 것이 효율적일 수 있다. 그러나 만약 패킷이 잘 도착했는데 ACK가 손실되었다면 잘 도착한 패킷을 다시 전송해야 한다는 것이 단점이 될 수 있다. 따라서 Go-back-N방식과 Selective Repeat 방식을 섞어서 사용하는 것이 요즘의 추세이다.
TCP segment 형식
TCP 프로토콜은 수행하는 일이 많기 때문에 세그먼트의 헤더에 들어가는 정보가 많다. 기본적으로 20Byte의 헤더 길이를 가지고 있고 필요한 경우에는 추가적으로 헤더를 더 붙일 수 있다.
- Source 포트번호
- Destination 포트번호
- Sequence Number
현재 segment가 담고있는 데이터가 전체 메세지에서 어떤 부분에 해당하는가를 나타내는 필드이다. 데이터를 전송할 때 통째로 보내지 않고 일정한 크기의 segment로 잘라서 첫번째 부분은 첫번째 segment에 넣고 차례차례 segment에 넣어서 순서대로 전송하게 된다. segment가 수신되면 이 sequence number를 통해 세그먼트의 순서를 맞추어 전체 메세지를 구성한다. Sequence Number은 두 연결의 당사자가 어떤 번호부터 시작하기로 결정한다. 만약 세그먼트의 크기가 100byte로 나누어져 있고 sequence number가 n으로 시작한다면 두번째 segment는 n+100이라는 sequence number를 가질 것이다.
- ACK Number
Reciever가 받아야하는 segment의 sequence number를 담는 필드이다. 만약 첫번째 segment가 도착하였고 그에 대해 잘 도착하였다는 것을 알려야 하고 동시에 n+100의 segment를 보내야 한다는 정보를 이 필드에 담아 송신측에 전달한다. 맨 처음 연결을 시작할 때 이 필드에 들어가는 내용은 의미가 없다. 그렇지만 헤더의 필드는 꼭 32bit만큼 값을 가지고 있을 것이다. 이 필드의 값이 의미있는 값인지 아닌지를 알리기 위해 Flag 값의 ACK 를 0또는 1로 설정한다.
- 헤더 길이
TCP의 경우 헤더에 옵션이 더 붙을 수 있다. 헤더의 길이가 항상 20byte가 아니기 때문에 어디서부터가 실제 데이터인지를 알려주는 필드이다. 전체 Segment에서 데이터가 어디서부터 시작하는지를 알려준다.
- 제어(Flag)
제어 플래그에는 기본적으로 여섯개가 있고 TCP 버전에 따라 9개의 플래그를 사용하는 경우도 있다.
ACK 플래그가 0이라면 헤더의 ACK number에 있는 값이 무의미함을 의미하고, 1이라면 유의미함을 의미한다.
RST,SYN,FIN 플래그는 TCP 연결을 설립하고 해제하는 데에 필요한 내용이다.
TCP는 신뢰성 있는 연결을 하기 위해 3-way handshaking을 한다. 이것은 연결을 위한 동의이다. 클라이언트가 연결을 요청하고, 서버가 그 요청에 대한 수락을 응답한다. 그리고나서 클라이언트는 그 응답을 받았다는 응답을 한번 더 함으로써 비로소 데이터 전송이 시작되는 것이다.
그렇다면 왜 2-way handshake를 하지 않는 것일까? 만약 2방향으로 연결을 설정하면 클라이언트는 서버에게 연결 요청을 하고 서버는 그것에 대한 응답을 함으로써 연결이 확립된다. 이때 만약 서버에 들어온 요청이 타이머를 초과해서 재전송된 요청이라면 그리고 클라이언트-서버 연결이 끝난 상황이라면 해당 요청은 연결이 확립되면 안되는 요청이다. 이 요청이 유효한 지 판단하기 위해서 서버는 클라이언트의 연결 요청에 대해 다시 한 번 클라이언트가 가용상태인지 확인해야 한다. 따라서 클라이언트는 가용상태임을 서버가 알 수 있도록 한번 더 응답해야 한다.
연결을 요청하는 클라이언트가 SYN bit를 1로 설정하고 sequence num을 x로 설정해서 세그먼트를 보내면 수신측은 이 내용에 대한 ACK를 보낸다. 이때 서버측이 전송하는 세그먼트의 헤더에도 SYN bit가 1로 설정되고, ACKbit도 1로 설정된다. 여기서 ACKnum은 x+1이 된다. TCP는 양방향 연결이기 때문에 서버도 sequence num를 y로 설정하여 보낸다. 그럼 클라이언트측은 이제 ACK bit를 1로 설정하고 ACKnum을 y+1로 하여 연결이 성립되었다는 것을 알린다.
연결을 해제할 때에는 4-way handshake를 하는데 이때 FIN 플래그를 이용한다. 클라이언트가 데이터 전송을 마쳤다면 FINbit를 1로 하고 패킷을 전송한다. 그 패킷에 대해 서버가 응답하면 클라이언트에서 서버로 향하는 연결이 종료된다. 그러나 여전히 서버에서 클라이언트로의 연결은 남아있다. 아직 서버가 보낼 데이터가 남아있을 수도 있기 때문이다. 서버에서 더이상 보낼 데이터가 없으면 FIN bit를 1로 설정하여 패킷을 보내고 클라이언트는 그에 응답함으로써 연결이 종료된다.
RST 플래그는 만약 연결을 수립하고자 할 때에 수신측에 연결하고자 하는 포트 번호를 가진 프로세스가 없다면 RST bit를 1로 하여 클라이언트에게 보내 다른 정보로 연결을 요청하라고 알리게 된다.
- Window 크기
수신자가 수용할 수 없을 만큼 너무 빠르게 패킷을 전송하면 수신측의 처리속도가 느리므로 버퍼가 오는 데이터를 다 수용하지 못한다. 버퍼의 크기를 넘는 데이터가 수신되면 데이터가 버려지게 된다. 그래서 이를 막기 위해 Flow Control(흐름 제어)를 한다. 어떤 호스트가 다른 호스트에게 패킷을 전달할 때 수신 버퍼에서 수용할 수 있는 버퍼의 크기를 이 필드에 담아서 보낸다. 그럼 이 호스트에게 데이터를 보낼 때 수용할 수 있는 window 크기를 넘지 않는 데이터를 보냄으로써 버퍼의 오버플로우를 방지하고 흐름제어를 하게 된다. 그리고 OS는 네트워크 혼잡 정도에 따라 이 윈도우 크기를 재설정하게 된다. rwnd가 수용 가능한 버퍼의 공간이므로 이 크기를 필드에 담아서 보내게 되는 것이다.
많은 소켓 프로그램에서 recieve 버퍼 사이즈의 크기를 4096 byte 정도로 할당한다.
- Checksum
전송된 segment에 오류가 있는지 검사할 수 있는 필드이다.
- 추가적인 option
연결 기반의 전송
위에서 말했듯 TCP는 연결을 수립할 때에 3-way handshake를 하고 연결을 해제할 때에는 4-way handshake를 한다. 그렇다면 실질적인 데이터 교환은 어떻게 진행되는 지 알아보자.
데이터를 보낼 때 seq num을 x라고 하고, 데이터의 크기를 a라고 하자. 그러면 받는 쪽은 ack num을 x+a로 설정하여 보낸다. 즉 다음에 받아야 할 데이터의 seq num을 보내게 된다. 또한 TCP는 양방향 통신으로 받은 쪽도 seq num을 보내게 되고 보내는 쪽도 그에 대한 ACK를 보낸다. 위 그림은 호스트 A가 B에게 보내는 데이터를 다시 반복하는 통신의 예시이다.
실질적으로 신뢰성있는 전송을 위해 Go-back-N 방식과 Selective Repeat방식을 절충하여 사용한다. Throughput을 위해 pipeline 방식으로 데이터를 전달하고, 각각의 패킷에 대한 개별ACK를 사용하지 않고 누적 ACK를 사용한다. 마찬가지로 하나의 타이머를 가지고 서비스를 하게 된다. 이러한 형태는 Go-back-N 방식을 닮았다. 그러나 패킷이 순서대로 도착하지 않아도 recieve 버퍼가 수용하는 범위 내에서 뒷순서의 패킷을 보관해둔다. 이러한 점에서는 Selective Repeat 방식과 유사하다.
송신자는 응용층의 데이터를 받으면 세그먼트를 만들면서 시퀀스 번호를 부여한다. 수신자에게 세그먼트를 보낸 후에 타이머를 설정한다. 수신자가 송신자로부터 데이터를 받으면 checksum을 비트 에러를 체크하고 에러라면 NAK 재전송을 요구한다. 만약 비트에러가 없다면 시퀀스 번호를 검사하여 순서가 맞으면 누적 ACK를 보낸다. 그리고 받은 패킷이 중복이라면 버린다. 송신자가 ACK를 받으면 윈도우에 ACK 번호를 재설정한다. ACK를 받지 않은 세그먼트들이 윈도우에 있다면 타이머를 시작한다. 만약 타이머가 종료되면 세그먼트를 재전송하고 타이머를 설정한다.
타이머의 시간이 너무 짧으면 많은 재전송이 일어나고 타이머의 시간이 너무 길면 손실에 대한 대처가 너무 느리게 일어나기 때문에 문제가 된다. 따라서 타이머의 시간을 적절히 설정해야 한다. 타이머는 TCP 연결의 두 개체 사이의 물리적으로 오가는 시간인 RTT(Round Trip Time)을 고려하여 그 시간보다는 길게 잡아야 할 것이다. RTT값은 네트워크의 혼잡정도에 따라 변하므로 고정적이지 않다. 따라서 몇번의 데이터 전송을 시도하고 평균적인 RTT 값을 계산하여 safety margin을 조금 더 더해서 타이머 시간을 설정한다.
그러나 타이머시간을 적절히 설정해도 손실에 대한 대처가 느리기 때문에 이를 보완하기 위한 한가지 방법이 있다. 송신자는 윈도우 사이즈에 따라 세그먼트를 한번에 여러 개 보낸다. 만약 중간에 한 세그먼트가 손실되고 뒤의 세그먼트가 잘 도착하여도 누적 ACK 방식을 사용하기 때문에 계속 똑같은 ACK를 재전송하게 된다. 그래서 TCP 에서는 타임아웃이 되기 전이어도 첫번째로 온 정상적인 ACK를 제외하고 세 번의 중복 ACK.가 도달하면 그 패킷을 재전송한다. 이것을 fast retransmit라고 한다.
다시 말해, TCP애서 재전송은 timeout이 발생하였을 때와 3개 이상의 중복 ACK를 받았을 때 발생한다.
흐름제어 (Flow Control)
TCP는 end system에서 데이터를 처리할 수 있을 만큼만 전송하도록 제어한다. 윈도우사이즈에 대한 정보를 헤더에 포함하여 받을 수 있는 데이터의 크기를 제어하는 것이다.
송신 버퍼의 범위는 수신 측의 여유 버퍼 공간을 반영하여 동적으로 바뀐다. 이러한 윈도우를 슬라이딩 윈도우라고 한다. 윈도우를 사용할 때 송신 응용프로그램이 전송하는 데이터의 크기가 너무 작고 수신측의 처리 속도가 느리면 비정상 윈도우 신드롬이 발생한다. 1바이트의 데이터를 전송하기 위해 40byte의 프로토콜 헤더를 붙이게 되어 최악의 전송효율으 나타내는 것이다.
이를 해결하기 위해 Nagle 알고리즘을 사용한다. 전송할 데이터를 어느정도 모아서 한 번에 전송하는 것이다. 이 알고리즘을 사용하면 송신측은 응용프로그램으로부터 받은 데이터가 최대 세그먼트 크기가 될 경우, 수신측으로부터 확인 응답을 받은 경우, 타이머가 완료된 경우에만 데이터를 전송한다. 또한 이 알고리즘은 네트워크와 응용프로그램의 데이터 처리 요구를 동시에 고려한다. 네트워크 속도가 빠르면 크기가 작은 세그먼트가 생기더라도 빠르게 처리할 수 있으니 바로 전송하고, 네트워크 속도가 느리면 데이터를 모아 전송하도록 하여 불필요한 오버헤드를 줄인다. Naglet 알고리즘은 실시간 통신 서비스에서 사용한다.
혼잡 제어(Congestion Control)
TCP 프로토콜은 네트워크 상에서의 트래픽 문제에 대해 혼잡을 제어하는 기능을 제공한다. 네트워크가 확장되면서 오가는 패킷량이 많아지자 문제가 발생하였다. 트래픽 양이 적으면 패킷이 잘 전달되었지만 트래픽 양이 매우 많아지니 실제 전달되는 양이 0으로 줄어드는 결과가 발생한다. 왜냐하면 트래픽이 많아지면 네트워크에서 처리해야 할 데이터의 양이 많아지고, 패킷의 지연시간도 길어지게 된다. 지연시간이 길어지면 timeout으로 인한 재전송이 또 일어나서 계속해서 패킷이 쌓이게 되면서 아무것도 처리되지 못하는 것이다. Flow control과는 다르게 congestion control은 네트워크를 공유하고 있는 모든 node들의 문제이므로 전역적인 문제이다. 혼잡 제어를 위한 방법을 크게 두가지로 분류하면 End-to-end 방식과 Network-assisted 방식이다.
End-to-End 방식
네트워크의 피드백 없이 End system인 TCP에서 독자적으로 해결하는 방식이다. 라우터가 전혀 관여하지 않고 호스트들이 자기가 보낸 데이터가 얼마나 잘 도달하는가 관찰하여 네트워크의 혼잡도를 판단하고 해결하는 것이다. TCP는 end-to-end 방식을 사용한다. 이는 반응형 혼잡 제어 방식으로 네트워크에서 체증이 발생할 때 지연시간, 라우터 버퍼의 길이를 계속 측정하여 트래픽 양을 감소한다. 라우터에서 하는 일이 너무 많기 때문에 TCP에서 수행하게 되었다.
혼잡 제어를 하기 위한 해결방식은 대표적으로 AIMD(Additive Increase Multiplicative Decrease) 철학을 따른다. 패킷을 한개 보내고 문제 없으면 보내는 수를 계속 늘린다. 만약 손실이 일어나면 패킷 전송량을 과감하게 1/2로 줄이는 방식이다. 추가할 때는 조금씩, 줄일때는 과감하게 하는 것이 이 AIMD 원칙이다.
TCP에서는 Awnd(advertised window)와 Cwnd(Congestion window) 이 두가지 윈도우를 사용한다. Awnd는 End system의 버퍼 중 비어있는 공간의 크기를 말하고, Cwnd는 네트워크가 혼잡을 일으키지 않는 한도 내에서 ACK를 받지 않고 한번에 전송할 수 있는 데이터의 양을 말한다. Cwnd는 네트워크 혼잡상황에 따라 다양하게 변화한다. TCP 흐름 제어를 위해서는 Awnd만큼 패킷을 전송할 수 있지만, 혼잡제어를 위해서는 Cwnd 만큼 전송할 수 있다. 초기에는 Cwnd를 1로 설정한다. 송신자가 Ack를 받을 때마다 Cwnd는 2배씩 증가한다. cwnd는 Awnd 사이즈 만큼 증가할 수 있다. 흐름제어와 혼잡제어는 동시에 수행되는 것이다.
TCP는 송신한 패킷에 대하여 ACK를 수신해야 하는데 timeout이 발생할 때 까지 ACK가 도착하지 않으면 혼잡이 발생한 것으로 예측한다. TCP는 혼잡과 상관 없이 패킷의 전송량을 처음에는 적은양으로 했다가 점차적으로 늘리는(slow start)를 한다. 그러나 계속 slow start로 패킷 전송량을 늘리면 congestion이 금방 발생하게 된다. 따라서 혼잡을 회피하고자 방식을 도입하였다. 이전에 혼잡이 발생하였던 window size의 절반값을 slow-start threshold로 설정한다. 이 threshold값에 도달하면 전송량을 1씩 증가하는 additive increase 방식을 취한다. 만약 혼잡이 발생한다면, 패킷 전송량을 아래와 같은 순서로 감소시킨다.
1) threshold = Cwnd/2로 설정한다.
2) cwnd를 1로 설정하고 slow start를 다시 시작한다. cwnd가 아까 설정한 threshold가 같아질 때까지 수행한다.
3) cwnd가 threshold보다 커지는 순간부터는 패킷전송량을 1씩 증가시킨다.
TCP는 동일한 ACK를 3개 받는 경우에 바로 재전송하는 fast retransmit를 수행함과 동시에 fast recovery를 수행한다. fast recovery는 Cwnd를 1/2로 줄이고 줄인 cwnd에서부터 선형적으로 증가시킨다.
Network-assisted 방식
네트워크 계층의 라우터가 호스트들에게 혼잡에 관한 정보를 피드백해주는 방식이다. 대표적으로 ATM이 이 방식을 사용한다. ip 헤더의 ㄸ추 bit를 00으로 설정하여 전송한다. 중간의 라우터에서 네트워크 혼잡이 발생하면 라우터에서 ECN bit를 11로 설정한다. 그러면 수신측은 TCP ACK segment의 ECE 플래그값을 1로 설정하여 송신측에게 전달함으로써 네트워크가 혼잡하다는 것을 알린다.
스트림통신
TCP 서비스는 데이터를 바이트 단위로 나눠서 전송하는 스트림 기반의 프로토콜이다. 두 개의 프로세스가 가상의 채널로 연결되어 있고, 송신 프로세스는 바이트 스트림을 생성(쓰기)하고 수신하는 프로세스는 바이트 스트림을 소비(읽기)한다.
'CS지식 > 컴퓨터네트워크' 카테고리의 다른 글
소켓 프로그래밍 과제 2번 (0) | 2023.05.23 |
---|---|
소켓 프로그래밍 과제 1번 (0) | 2023.05.13 |
Transport Layer(전송계층), UDP (0) | 2023.04.28 |
Application Layer_ P2P, CDNs, socket programming (0) | 2023.04.22 |
Application Layer_ Email, DNS, FTP (0) | 2023.04.22 |