TCP는 연결 지향형 프로토콜로, 데이터 전송 전후에 Handshake 과정을 거쳐 연결을 수립하고 종료한다.
또한 데이터 전송의 신뢰성과 순서 보장을 위해 흐름 제어, 오류 제어, 혼잡 제어와 같은 기법을 사용한다.
클라이언트와 서버가 연결을 맺는 과정

| 단계 | 동작 | 상태 변화 |
|---|---|---|
| 1 | 클라이언트 → 서버: SYN 전송 (연결 요청) | 클라이언트 → SYN_SENT |
| 2 | 서버 → 클라이언트: SYN + ACK 전송 (요청 수락) | 서버 → SYN_RCVD |
| 3 | 클라이언트 → 서버: ACK 전송 (응답) | 클라이언트·서버 → ESTABLISHED |
결과: 양쪽 모두 ESTABLISHED 상태가 되어 데이터 송수신 가능.
연결이 수립된 이후, 데이터를 주고받는 과정
ACK 전송ACK를 받지 못하면 재전송 수행연결을 끊는 과정

| 단계 | 동작 | 상태 변화 |
|---|---|---|
| 1 | 클라이언트 → 서버: FIN 전송 (종료 요청) | 클라이언트 → FIN_WAIT1 |
| 2 | 서버 → 클라이언트: ACK 전송 | 서버 → CLOSE_WAIT, 클라이언트 → FIN_WAIT2 |
| 3 | 서버가 남은 데이터 전송 후 FIN 전송 | 서버 → LAST_ACK |
| 4 | 클라이언트 → 서버: ACK 전송 | 클라이언트 → TIME_WAIT |
| 5 | 일정 시간 대기 후 클라이언트 CLOSED, 서버는 ACK 수신 시 CLOSED |
수신자의 처리 속도를 고려해 송신 속도를 조절
전송 도중 데이터 유실·오류 발생 시 복구
네트워크 상태가 불안정할 때 전송량을 조절하여 네트워크 과부하를 방지
Wireshark는 패킷을 실시간으로 캡처하고, 각 패킷의 세부 내용을 분석할 수 있는 네트워크 프로토콜 분석 도구이다. Wireshark를 이용해 TCP 연결 과정과 종료 과정을 실제 패킷 캡처를 통해 살펴보았다.
curl -v http://example.com/ 요청을 보내고 어떤 패킷이 오고가는지 확인해보자.
다음은 Wireshark에서 ip 주소를 가지고 필터링한 결과이다.





Seq(Sequence Number)는 보내는 데이터의 순서 번호이다. 각 TCP 세그먼트의 시작, 즉 첫번째 바이트 번호를 의미한다. 받은 마지막 바이트 순서 번호에 1을 더한 값이 된다.
Ack(Acknowledgement Number)는 상대가 보내주길 기대하는 다음 바이트 번호를 의미한다. 즉 받은 마지막 바이트 순서 번호에 1을 더한 값이 된다.
결과를 다시 살펴보자.
클라이언트가 HTTP 요청을 보내고 나니 Ack=75가 되었다.

요청을 확인해보니 길이가 74이다. 따라서 서버가 기대하는 다음 바이트 번호는 75가 되므로, Ack=75가 된다.

이후 서버가 보낸 ACK 패킷에는 Seq=1로 변함이 없다.
그럼 언제 Seq가 증가하는거지?
확인해보니 데이터 전송(HTTP 요청/응답), SYN/FIN에 의해서만 증가한다. ACK는 Seq에 영향을 주지 않는다!
그리고 클라이언트와 서버는 독립적인 Seq 번호를 유지한다. (이 부분이 참 헷갈렸다...)
클라이언트만 따로 보자.

즉, 각각 자신의 Seq를 따로 증가시키고, Ack는 상대의 Seq에 맞춰 증가한다.