TCP란 OSI 7계층 중 4계층인 전송계층에 속하는 프로토콜이다
TCP의 특징
1. 연결 지향 프로토콜
2. 신뢰성 있는 프로토콜
3. 오류 제어
4. 혼잡 제어
전송계층의 또다른 프로토콜인 UDP는 속도를 중요하게 여긴다면 TCP는 신뢰성을 중요하게 여긴다고 볼 수 있다
TCP 헤더 구조 (기본 20바이트 + 옵션 필드)
| 필드 이름 | 크기 (비트) | 설명 |
|---|---|---|
| Source Port | 16 | 송신 측 포트 번호 |
| Destination Port | 16 | 수신 측 포트 번호 |
| Sequence Number | 32 | 현재 세그먼트의 시작 바이트 번호 |
| Acknowledgment Number | 32 | 다음에 받을 것으로 예상되는 바이트 번호 |
| Data Offset | 4 | TCP 헤더의 길이 (단위: 32비트) |
| Reserved | 3 | 예약된 비트 (항상 0) |
| Flags | 9 | 제어 비트 (SYN, ACK 등) |
| Window Size | 16 | 수신 측 버퍼 크기 (흐름 제어) |
| Checksum | 16 | 오류 검사용 값 |
| Urgent Pointer | 16 | 긴급 데이터 끝 위치 (URG 플래그일 때 사용) |

※ 헤더 뒤에 옵션 필드가 붙을 수 있다 (예: MSS, Timestamp 등)
🏳️ TCP 플래그 (Flags) - 9개 비트
TCP는 신뢰성 있는 데이터 전송을 위해 연결 지향 방식을 사용한다
이 연결은 3-way-handshake라는 과정을 통해 설정되며 클라이언트와 서버가 서로 데이터를 주고받을 준비가 되었는지 확인하고, 초기 시퀀스 번호(ISN: Intial Sequence Number)를 교환하여 통신을 안정적으로 시작할 수 있게 된다.
| 플래그 | 설명 |
|---|---|
| URG (Urgent) | 긴급 데이터 여부 |
| ACK (Acknowledgment) | 응답 번호 유효 여부 |
| PSH (Push) | 즉시 전달 요청 |
| RST (Reset) | 연결 재설정 요청 |
| SYN (Synchronize) | 연결 시작 요청 |
| FIN (Finish) | 연결 종료 요청 |
| ECE (ECN-Echo) | ECN 혼잡 알림 응답 |
| CWR (Congestion Window Reduced) | 혼잡 제어 응답 |
| NS (Nonce Sum) | ECN 관련 실험 비트 (거의 사용 안 함) |
3-way-handshake과정

1단계 클라이언트 -> 서버: 연결 요청(SYN)
클라이언트는 서버에게 연결 요청을 위한 패킷을 전송한다. 이 패킷은 tcp 헤더의 syn플래그가 설정된 상태로 전송된다. 클라이언트는 이때 초기 시퀀스 번호(ISN)을 임의로 생성하여
SEQ필드 (sequence number field)에 담는다. 서버는 이 패킷을 수신함으로써 클라이언트가 연결을 요청하고 있다는 사실을 인식한다.
2단계
서버 -> 클라이언트: (SYN + ACK) 클라이언트의 연결 요청(SYN)에 대한 확인 응답(ACK) + 서버의 연결 요청(SYN)
서버가 클라이언트의 연결요청(SYN)에 대해 응답(ACK)을 보냄과 동시에 클라이언트에게 자신도 연결을 요청한다는 의미로 연결 요청(SYN)을 전송한다.
3단계
클라이언트 -> 서버: 응답확인(ACK)
클라이언트는 서버의 SYN + ACK 패킷을 수신한 후, ACK 플래그만 설정된 패킷으로 응답한다.
예시
시퀀스 번호와 ACK 번호의 의미와 증가 원리
1단계에서 클라이언트가 보낸 SYN 패킷의 시퀀스 번호가 1000이라고 가정하자.
서버는 이 값을 받고, 상대방이 보낸 데이터를 정상적으로 받았다는 의미로 1000 + 1 = 1001을 ACK 번호로 응답한다. 여기서 +1을 하는 이유는 SYN 패킷 자체가 1바이트 분량의 데이터처럼 취급되기 때문이다. 하지만 항상 ACK 번호가 1씩만 증가하는 것은 아닙니다.
만약 클라이언트가 시퀀스 번호 1000부터 시작해서 100바이트짜리 실제 데이터를 보냈다면,
서버는 그 데이터를 모두 받았다는 의미로 ACK 번호를 1000 + 100 = 1100으로 응답한다.
3-way-handshaking 과정에서 데이터가 들어갈 일은 없지만 +1을 하는 이유가 데이터 크기만큼이다라는 것을 명확하게 하기 위함이다.
즉, ACK 번호는 수신자가 정상적으로 받은 마지막 바이트의 다음 번호를 가리키며,
“여기까지 데이터는 다 받았으니 다음부터 이 번호(ACK 번호)부터 다시 보내줘”라는 의미를 갖는다.
요약하면,
SYN, FIN 같은 제어 패킷은 1바이트 데이터로 간주되어 ACK 번호가 +1 증가한다.
실제 데이터가 전송될 때는 전송한 데이터 크기만큼 ACK 번호가 증가한다.
연결 설정을 하는 과정이 있다면 연결을 종료하는 과정도 존재한다 그게 바로 4-way handshake 이다. 4-way-handshaking을 통해 연결을 안전하고 정확하게 끊을 수 있다.

1단계
클라이언트 -> 서버: FIN (연결 종료 요청)
연결을 종료하고자 하는 쪽(예: 클라이언트)이 TCP 헤더에 FIN 플래그를 설정한 패킷을 보낸다.
이 패킷은 “나는 이제 데이터 전송을 마쳤고 연결을 종료하고 싶다”는 신호이다.
이때 시퀀스 번호(SEQ)는 클라이언트가 마지막으로 보낸 데이터의 다음 번호를 나타낸다.
2단계
서버 -> 클라이언트: ACK (종료 요청 수락)
서버는 클라이언트가 보낸 FIN 패킷을 받고, ACK 플래그를 설정하여 응답합니다.
이 ACK 번호는 클라이언트의 FIN 시퀀스 번호 + 1로 설정되어, “FIN 요청을 받았고 승인했다”는 의미를 전달한다.
이 시점에서 서버는 아직 데이터 전송이 완료되지 않았을 수 있으므로, 연결이 완전히 종료된 것은 아니다.
3단계
서버 -> 클라이언트: FIN (서버 측 연결 종료 요청)
서버가 자신의 데이터 전송을 모두 마쳤으면, 이제 서버도 FIN 플래그가 설정된 패킷을 클라이언트에게 보냅니다.
이 패킷은 “나도 데이터 전송을 끝냈고 연결 종료를 원한다”는 신호이다.
서버 역시 자신의 FIN 시퀀스 번호를 포함한다.
4단계
클라이언트 -> 서버: ACK (서버 FIN에 대한 응답)
클라이언트는 서버의 FIN 패킷을 받고, ACK 플래그가 설정된 패킷으로 응답한다.
ACK 번호는 서버의 FIN 시퀀스 번호 + 1로 설정되어, 서버의 연결 종료 요청을 승인했다는 의미이다.
위 4단계 과정에서 클라이언트는 더 이상 보낼 데이터가 없어 FIN을 보내면 즉시 송신은 종료되고 수신만 가능한 상태가 된다. 반면 서버는 아직 보낼 데이터가 남아 있을 수 있기 때문에, 2단계와 3단계 사이에 데이터를 추가로 전송할 수 있다. 이때 데이터 전송 시에는 3-way handshake 과정에서 설명한 것처럼 SEQ가 데이터 크기만큼 증가하며, 수신 측은 받은 데이터 크기만큼 ACK 번호를 증가시켜 응답한다. 데이터를 다 보냈다면 이제 4-way handshake 3단계, 4단계를 실행하여 완전히 연결을 종료할 수 있다.
이처럼 TCP의 3-way handshake를 통해 신뢰성 있는 연결을 설정하고, 4-way handshake를 통해 양방향 데이터 전송이 완전히 종료된 후에 안전하게 연결을 종료함으로써 데이터 손실 없이 안정적인 통신이 가능하다.