1. TCP(Transmission Control Protocol)
- 전송계층(Transport Layer)의 연결 지향형 프로토콜
- 두 호스트간에 통신을 위한 논리적 연결(가상회선)을 수립하여 통신
- 3-way handshaking 으로 연결을 수립, 4-way handshaking으로 연결을 해제
- 신뢰성있는 데이터 전송(Reliable Data Transfer)을 지원
- 데이터의 순서유지 보장
- 흐름제어(수신측의 처리속도에 맞춰 전송속도 조절) 지원
- 혼잡제어(망의 혼잡도에 따라 전송 패킷량 조절) 지원
- 양방향(Full Duplex), 1:1(Point to Poin) 통신
2. UDP(User Datagram Protocol)와의 비교
TCP | UDP | |
신뢰성 보장 | O | X |
순서 유지 | O | X |
에러 검출 | O | O |
흐름 제어 | O | X |
혼잡 제어 | O | X |
연결 과정 | O | X |
통신 형태 | 1:1(Point to Point), 양방향(Full Duplex) | 1:1, 1:N(Broadcast), N:M, 단방향(Simplex) |
통신 단위 | 바이트 스트림(데이터 유실이 없기 때문) | 데이터그램 |
3. 헤더
① UDP
- Port(32bit) : source(송신측) 포트와 dest(수신측) 포트 두 종류가 있으며 각각 16비트씩 차지
- Segment Length(16bit) : 헤더를 포함한 UDP 세그먼트의 길이 정보
- Checksum(16bit) : 전송 도중에 에러가 발생했는지 판단하기 위한 값. UDP는 에러가 발생한 segment를 drop
- Port(32bit) : source(송신측) 포트와 dest(수신측) 포트 두 종류가 있으며 각각 16비트씩 차지
- Sequence Number(32bit) : 전송되는 데이터의 순서. 데이터의 순서 유지를 보장하기 위한 값
- Acknowledgement Number(32bit) : 수신자가 받을 것으로 기대하는 다음 데이터의 시퀀스번호
- Data Offset(= Header Length)(4bit) : 헤더가 아닌 데이터(본문)가 시작되는 위치. 단위는 word(=32bit)
=> 맨 마지막 필드인 Option의 경우 길이가 정해져있지 않기 때문에 이 필드가 필요하다. - Reserved(3bit) : 나중을 위해 예약된 필드. 현재는 그냥 0으로만 채워지는 상태
- Flags(9bit) : 세그먼트의 속성을 표현하는 플래그
- URG : Urgent Pointer 필드에 값이 채워져있음을 표시
- ACK : Acknowledgement 필드에 값이 채워져있음을 표시. 이 플래그가 0이라면 해당 필드를 무시
- PSH(Push) : 수신측에게 이 데이터를 최대한 빠르게 애플리케이션에 전달할 것을 요청.
이 플래그가 0이라면 수신측은 버퍼가 채워질 때 까지 대기 - RST(Reset) : 이미 연결이 확립된 상대에게 연결을 강제로 리셋해달라고 요청
- SYN(Synchronized) : 상대방과 연결을 확립할 때 시퀀스 번호의 동기화를 맞추기 위한 세그먼트임을 표시
- FIN(Finish) : 연결 종료 요청을 위한 세그먼트임을 표시
- NS, CWR, ECE : 명시적 혼잡 통보(ECN)를 위한 플래그. 혼잡 제어 기능의 향상을 위한 플래그
- Window Size(16bit) : 한번에 전송 가능한 데이터의 양을 의미. 즉, 윈도우의 최대 크기는 (2^16 - 1) 바이트
- Checksum(16bit) : 데이터 송신중 에러가 발생했는지 검출하기 위한 값. 에러 발생시 재전송을 요청하기 위함
- Urgent Pointer(16bit) : 긴급 포인터. URG 플래그가 1이라면 해당 포인터가 가리키는 데이터를 우선처리
- Option(~40 bytes) : TCP의 기능 확장을 위해 사용되는 필드. TCP 헤더의 최대 길이가 60 bytes 이고 고정 필드의
길이가 도합 20 bytes 이기 때문에 Option 필드의 최대 길이는 40bytes가 된다.
4. 신뢰성 있는 데이터 전송(Reliable Data Transfer) / 데이터의 순서유지 보장
- 송신측은 데이터 패킷을 전송한 뒤 타이머를 설정
- 수신측이 데이터를 받으면 응답으로 다음에 받아야할 패킷의 시퀀스 넘버를 명시한 ACK을 전송
- 이때, ACK를 보낼 때 응답 데이터를 보낼 가능성을 생각하여 수신 후 ACK을 보낼 때 까지 딜레이를 둔다.
- 송신측이 ACK를 받으면 데이터가 정상적으로 전달된 것을 확인, ACK에 명시된 다음 패킷을 전송
- ACK를 받지 못하고 타임아웃이 발생하면 데이터가 전달되지 않은것으로 간주, 데이터 패킷을 재전송
5. 흐름 제어(Flow Control)
① Stop and Wait
- 하나의 패킷을 보낸 뒤 해당 패킷에 대한 ACK가 돌아오기까지 대기
- 패킷 전송마다 ACK를 기다리는 방식으로는 패킷 전송 이후 응답이 돌아오기 까지의
RTT(Round Trip Time)만큼 시간을 낭비
② Sliding Window
- 지정된 갯수(윈도우 크기)만큼의 패킷은 하나하나 ACK를 기다리지 않고 전송하는 Pipeline 방식을
사용하는 것으로 성능향상 가능
6. Pipeline 방식을 사용할 때의 신뢰성 보장
Pipelined 방식을 실제로 구현하려면 한번에 얼마만큼의 패킷을 연속적으로 보낼 것인지와
오류가 발생한 패킷을 어떻게 재전송할 것인지를 생각해야한다. 이에 대한 두 가지 접근법에 대해 알아보자.
① Go Back N (GBN)
- 사전에 윈도우(Window)의 크기를 임의로 정하여 윈도우의 크기만큼의 패킷을 연속으로 전송
- 수신측은 대기하고있던 순서에 해당하는 패킷이 아니면 discard, 마지막으로 받은 패킷에 대한 ack를 전송
=> 여기서 ACK은 마지막으로 전달받은 패킷의 시퀀스넘버이다.
실제 TCP에서의 ACK는 GBN과는 달리 다음에 받아야할 패킷의 시퀀스넘버를 명시한다. - 유실된 패킷에 대한 ack가 오지 않아 timeout이 발생하면 윈도우의 시작 위치를 timeout이 발생한
패킷으로 옮겨 윈도우의 크기만큼 재전송 - 수신은 정상적으로 됐지만 ACK만 유실된 경우 다음 ACK만으로도 이전 패킷이 정상적으로 전송됐음을
유추가능하기에 문제가 발생하지 않음 - 중간에 하나의 패킷만 유실되도 해당 패킷부터 다시 윈도우의 크기만큼 패킷들을 재송신하는
방식이기 때문에 그다지 효율적이지 못함
② Selective Repeat
- 수신측이 유실된 현재 기다리는중인 패킷이 아니어도 정상적으로 수신한 패킷을 버퍼에 저장하고
해당 패킷에 대한 ack를 전송 - 송신측은 timeout이 발생하면 해당 패킷을 재송신하고 이후 정상적으로 전송된 패킷에 대한 ack를
받더라도 timeout이 발생한 패킷들에 대한 ack가 도착하기 전까지는 윈도우를 이동하지 않으며
새로운 패킷을 보내지도 않음 - 수신측은 유실되었던 패킷을 수신하면 그동안 버퍼에 저장해두었던 다른 패킷들과 함께 정상적으로 패킷을
처리하고 유실되었던 패킷에 대한 ack를 전송 - 송신측은 timeout이 발생한 패킷에 대한 ack를 수신하면 윈도우를 이동하고 새로운 패킷을 전송
이때, 미리 ack를 받아두었던 패킷들도 모두 스킵하여 윈도우를 이동한다. - GBN에 비해 효율적이지만 구현이 복잡함, 수신측에도 버퍼 필요
- Selective Repeat 프로토콜의 딜레마
- Sequence Number 의 범위가 윈도우의 크기만큼일 경우 재전송한 데이터와 정상적으로 보낸
데이터를 수신측이 구분할 수 없게 되는 경우가 발생할 수 있음 - Sequence Number 의 범위를 더 넓혀야함 - 얼마만큼 넓혀야하는가
=> 윈도우 크기의 2배가량이 Sequence Number의 범위를 최소화하면서 문제를 해결할 수 있다.
- Sequence Number 의 범위가 윈도우의 크기만큼일 경우 재전송한 데이터와 정상적으로 보낸
- 실제 TCP는 윈도우 크기가 매우 크기때문에 모든 패킷에 일일히 타이머를 설정하는 것은 비현실적
=> GBN을 기반으로 조금 더 개선된 방식을 사용
7. 혼잡 제어(Congestion Control)
- 패킷이 전송되는 과정에서 네트워크가 혼잡상태에 빠질 경우 이를 감지, 패킷 전송량을 조절
- TCP의 경우 패킷의 유실을 통해 혼잡을 감지하고 혼잡 제어에 들어간다.
① AIMD(Additive Increase Multicative Decrease)
- 합증가/곱감소 알고리즘
- 처음에는 패킷을 주기마다 하나씩 보내는 것으로 시작
- 패킷이 정상적으로 보내질 경우 주기마다 1씩 전송량을 증가
- 윈도우 크기 증가여부는 이전에 윈도우 크기를 증가시킨 뒤 처음으로 보내진 패킷의 ACK로 판단한다.
- 패킷전송에 실패하거나 timeout이 발생할 경우 윈도우 크기를 절반으로 감소
=> 단순 패킷 유실의 경우 일부 패킷을 제외한 다른 패킷의 ACK이 도달하기에 구분 가능 - 초반에 패킷 전송량이 늘어나는데 너무 많은 시간이 걸림
- 네트워크의 혼잡을 미리 감지하지 못하고 혼잡이 발생하고나서 비로소
윈도우 크기를 절반으로 줄이는 방식
② Slow Start(Multicative Increase)
- AIMD와 마찬가지로 처음에는 패킷을 하나 보내는 것으로 시작
- 패킷이 정상적으로 보내질 경우 "모든 ACK마다" 1씩 전송량을 증가. 즉, 주기마다 윈도우 크기는 2배씩 증가
- 혼잡이 감지될 경우 해당 시점에서의 윈도우 크기를 기억하고 윈도우 크기를 1로 초기화
- 이후 혼잡이 감지된 시점의 윈도우 크기의 절반까지는 기존의 방식대로 주기마다 2배씩 증가
- 절반 이후부터는 선형적으로 주기마다 1씩 증가시키는 방식을 사용
- 초기 패킷 전송량을 빠르게 높여갈 수 있으며 한번 혼잡을 감지하고나면 AIMD보다 효율적인 혼잡제어가 가능
③ Fast Retransmit - 패킷유실에 대한 대처
- 수신측이 순서에 맞지 않는 패킷을 받았을 때도 ACK를 전송
- 이 때, ACK 값으로 마지막으로 순서를 지켜 들어온 패킷의 다음 패킷의 시퀀스 넘버를 담아
전송하는 것으로 송신측이 빠진 패킷만을 재전송하도록 할 수 있음 - 또한 재전송이 발생한 것으로 네트워크 혼잡을 감지하여 윈도우 사이즈를 조절할 수 있음
④ Fast Recovery - Slow Start의 윈도우 크기 복구에 걸리는 시간 개선
- 혼잡을 감지할 경우 윈도우 사이즈를 1로 줄이지 않고 반으로 줄이는 방식
- 이 방식에서는 혼잡이 발생하기 전까지는 Slow Start 방식을, 발생한 후에는 AIMD방식을 사용하게된다.
7. Nagle 알고리즘
if there is new data to send then
if the window size ≥ MSS and available data is ≥ MSS then
send complete MSS segment now
else
if there is unconfirmed data still in the pipe then
enqueue data in the buffer until an acknowledge is received
else
send data immediately
end if
end if
end if
- Pipelined Protocol에서 패킷 하나로 전송되는 데이터의 크기가 너무 작을 경우 데이터크기 대비 패킷량이
너무 많아지는 오버헤드가 발생 - 지정한 사이즈의 버퍼를 사용하여 이전에 보낸 패킷의 ack가 돌아오기 전까지 전송해야할 데이터는 버퍼에 저장
- ack가 돌아오면 버퍼에 넣어둔 데이터를 하나의 패킷으로 전송
- 이 방식을 사용할 경우 전송 속도는 느려지지만 전송되는 패킷의 수가 줄어들어 효율적인 통신이 가능하다.
- 빠른 응답속도가 요구되는 시스템에서는 nagle을 사용하지 않는 것이 좋을 수 있다.
- WAN 과 같이 규모가 크고 느린 네트워크 통신에서는 nagle을 사용하는 것이 효과적이다.
'CS > 네트워크' 카테고리의 다른 글
#8 Link Layer(Data Link Layer + Physical Layer) (0) | 2021.11.25 |
---|---|
#7 Network Layer (0) | 2021.11.18 |
#5 Application Layer 2 - HTTP (0) | 2021.11.01 |
#4 Socket Programming (0) | 2021.10.29 |
#3 Application Layer 1 - 소켓(Socket) (0) | 2021.10.28 |