주제 : TCP 훑어보기
TCP 특징
- Point-to-point
한 프로세스와 한 프로세스 간의 연결만 처리 (One Sender, One Receiver)
- Reliable, in-order byte stream : 신뢰 가능하게, 순서대로 처리
- pipelined : 한방에 쫙 쏟아서 보냄
- full-duplex data : 양쪽다 서로 보냄(ACK도 보내는거니까)
- Send & Receive Buffer : 양쪽 다 2개의 버퍼가 있음
- connection-oriented : 핸드세이크
- flow controlled : 소화할 수 있을만큼 조절하며 보냄
- Congestion controlled : 다음 시간에
TCP Segment
계층별로 데이터의 명칭이 다르다.
아래로 갈수록 위의 전체를 data 필드에 넣는 방식이라고 생각해라.
TCP 계층의 메시지를 Segment라고 부른다.
![](https://velog.velcdn.com/images/youngju307/post/1f5a687f-2ee3-4d32-bf96-dce5dc74f19d/image.png)
그렇다면 TCP에서 중요한 것은 뭘까?
보내는 data의 내용이 중요할까?
우편 배달부가 편지의 내용을 보냐 포장지를 보냐?
그렇다. 헤더가 존나 중요하다.
![](https://velog.velcdn.com/images/youngju307/post/f987f538-8f81-4c72-b63c-4a14800c2db8/image.png)
Segment의 구조는 매우매우 중요하다고 한다.
- Source Port (16 bits): 송신자의 포트 번호를 나타냅니다. 송신 애플리케이션이 사용하는 포트 번호입니다.
- Destination Port (16 bits): 수신자의 포트 번호를 나타냅니다. 데이터를 수신할 애플리케이션이 사용하는 포트 번호입니다.
- Sequence Number (32 bits): 데이터의 순서를 추적하는 번호입니다. 처음 연결 시에는 랜덤한 값으로 시작하며, 이후 전송된 바이트 수에 따라 증가합니다. 수신자가 데이터의 순서를 정확히 재조립할 수 있게 합니다.
- Acknowledgment Number (32 bits): 송신자가 수신한 데이터의 다음 예상 시퀀스 번호입니다. 이전에 받은 데이터에 대한 확인 응답을 나타냅니다.
- Data Offset (4 bits): TCP 헤더의 크기를 나타냅니다. 일반적으로 20 바이트가 기본이지만, 선택적으로 헤더가 확장될 수 있기 때문에 이 필드는 데이터가 시작되는 위치를 나타냅니다.
- Reserved (3 bits): 미래의 용도를 위해 예약된 필드입니다. 현재는 항상 0으로 설정됩니다.
- Flags (9 bits): 연결 상태와 데이터 흐름을 제어하기 위한 플래그들입니다:
- URG: 긴급 포인터 필드가 유효함을 나타냅니다.
- ACK: Acknowledgment Number가 유효함을 나타냅니다.
- PSH: 수신자가 데이터를 즉시 전달해야 함을 나타냅니다.
- RST: 연결을 강제로 재설정합니다.
- SYN: 연결 설정 요청을 나타냅니다.
- FIN: 연결 종료 요청을 나타냅니다.
- Window Size (16 bits): 수신자가 한 번에 받을 수 있는 데이터의 양을 나타냅니다. 흐름 제어를 위해 사용됩니다.
- Checksum (16 bits): 헤더와 데이터의 무결성을 확인하기 위한 오류 검사 값입니다. 송신자는 이 필드를 계산하고, 수신자는 이 값으로 데이터가 손상되었는지 확인합니다.
- Urgent Pointer (16 bits): URG 플래그가 설정된 경우, 긴급 데이터의 끝을 나타냅니다. 일반적으로 잘 사용되지 않지만, 긴급 데이터를 처리할 때 유용합니다.
- Options (Variable Length): 선택적으로 사용하는 필드로, TCP 연결을 설정할 때 다양한 추가 정보를 제공하는 데 사용됩니다. 대표적으로 Maximum Segment Size (MSS)와 Window Scaling 옵션이 있습니다.
- Padding:
옵션 필드를 32비트 경계로 맞추기 위해 사용됩니다. 옵션 필드의 길이가 32비트로 나누어 떨어지지 않으면 패딩을 추가합니다.
다 필요없고, 핵심만 살펴보면
- Cummulative ACK : ACK10이면, 9까지 다 잘 받았고, 10을 내놓으라는 뜻이다.
- Seq # 는 다음 그림에서 쉽게 이해해보자.
TCP seq# & ACKs
![](https://velog.velcdn.com/images/youngju307/post/2871df82-8900-4c34-9c3e-34a145a5c0c0/image.png)
여기서 Seq#는 랜덤값으로 처음에 설정된다고 한다. 여기선 42다.
A가 보내는데 ACK=79로 보낸다. 응답할 때만 ACK 쓰는 거 아녔음?
TCP는 양방향 통신(full-duplex)이기 때문에, A가 보내는 동시에, 니 응답에 대해 여기까지 받았다는 ACK를 보낼 수도 있는 것이다.
아래 그림을 생각해보면 이해가 가능할 것이다.
![](https://velog.velcdn.com/images/youngju307/post/4b76c414-477d-4c37-9a80-c14b3497cb6b/image.png)
A의 ACK=79라면, B가 응답할 Seq#는 79일 것이고,
B의 ACK는 A의 Seq#인 42 + 1 = 43인 것이다. 이제 좀 감이 오는가?
Timer의 적절값을 어떻게 설정해야 좋을까?
찍는게 아니라, 당연히 메시지가 갔다가, 응답을 받는 시간까지를 참고하면 좋을 것이다.
이를 RTT라고 하는데, 대강 예상 시간 + 알파 라고 생각하고 넘어가자.
![](https://velog.velcdn.com/images/youngju307/post/8df21469-6c2f-4a4b-9219-5264a181a72e/image.png)
다양한 예제를 통한 이해하기
![](https://velog.velcdn.com/images/youngju307/post/57eaf56c-5a3f-42ef-a1b2-a16330899614/image.png)
![](https://velog.velcdn.com/images/youngju307/post/ef2b46b0-eab1-4685-9993-2d988bf5a183/image.png)
이 그림을 이해했다면, '아 굳이 모든 세그먼트에 대해 일일히 응답할 게 아니라, cummulative한 방식이니까 마지막 하나만 제대로 오면 되겠구나!'
라는 생각이 들 것이다.
타이머의 효율성과 연관되는데, 저 타이머가 너무 긴 것이다.
굳이 타이머를 안 맞추더라도, 예를 들어 0~100까지 쭉 보냈는데, 10번만 유실됬다고 가정하자.
그럼 Sender인 내가 받는 ACK은 어떻게 될까?
ACK1,ACK2...ACK10, 그리고 11,12,13을 리시버가 받아도 오는값은
ACK10,ACK10,ACK10 : 10 내놔 이 새끼야.
이렇게 되는것이고, 그럼 나는 '아 10이 중간에 유실됬구나' 알 수 있는 것이다.
이는 의무는 아니고, 이렇게 Duplicate ACK이 3번 오면 타이머 관계없이 다시보내라고 '권장'
한다고 한다.