유레카 2기 CS 스터디 네트워크 파트 메인 운영을 준비하며 쓴 글입니다:)
네트워크 기초 지식이 없더라도 최대한 잘 이해할 수 있도록 작성하기 위해 노력했습니다!

전송계층의 프로토콜
일반적으로 TCP와 IP는 함께 사용되며 IP는 배달을, TCP는 패킷의 추적 및 관리를 하게 됩니다.
TCP
신뢰할 수 있는 통신을 위한 연결형 프로토콜
UDP
독립적인 비연결형 프로토콜

비교 요약
UDP와 TCP는 각각 별도의 포트 주소 공간을 관리하므로 같은 포트 번호를 사용해도 무방합니다.
즉, 두 프로토콜에서 동일한 포트 번호를 할당해도 서로 다른 포트로 간주합니다.
정리해보면 다음과 같아요 😍
TCP | UDP |
---|---|
연결지향적 | 비연결지향 |
Unicast | Broadcast, Multicast |
중앙제어 | 분산제어 |
논리적 | 물리적 |
실시간으로 서로 연결 가능 | 경로를 연결해놓고 출발 |
ex. 전화 | ex. 엽서 |
TCP Segment

IP 헤더의 뒤부터 TCP Segment 정보가 들어있어요.
IP 헤더엔 IP 주소가, TCP 헤더엔 포트번호라는 주소 정보가 포함되어 있어요.
TCP Segment는 헤더와 데이터로 구성되어있어요. 이들은 각각 배달하려는 송장과 물품이라고 보면 됩니다!

IPv4 헤더는 고정 부분 20바이트와 가변 부분 0~40바이트로 구성되어 있습니다.
옵션을 지정하지 않았다면, 옵션 영역을 제외한 헤더의 최소 크기는 20바이트입니다.
port address
컴퓨터에서 실행되고 있는 서버를 구분 짓기 위한 논리단위
16비트(0~65536개). 주로 10진수로 표현합니다.
0~1023까지는 미리 지정되어 있어요. ⇒ 사용자는 1024 이후만 할당 가능합니다.
예를 들어 http 통신은 80번 포트를 사용하고, ssh 통신은 22번 포트를 사용합니다.
그러면 만약 다른 웹서버와 연결하고 싶다면? 포트번호를 url주소 뒤에 :8080
이렇게 붙여주면 됩니다!

Sequence Number (SEQ#)
보내는 Segment 내 byte stream에서 첫 번째 byte 번호
- 예를 들어, 1000바이트씩 데이터를 나누어 보낸다고 가정하면
- 첫 번째 세그먼트: SEQ# = 0 (0~999 바이트 전송)
- 두 번째 세그먼트: SEQ# = 1000 (1000~1999 바이트 전송)
- 간단 퀴즈!!
- TCP 연결이 5,000개의 파일을 전송한다고 가정합니다. 첫 번째 바이트는 10,001입니다. 만약 데이터가 각각 1,000바이트를 전송하는 5개의 세그먼트로 전송되는 경우 첫번째 전송 이후 각 세그먼트의 시퀀스 번호는 무엇인지 나열하시오. (힌트: 4개)
- 정답: 11001,12001,13001,14001
Acknowledge Number (ACK#)
상대방으로부터 받아야 하는 다음 TCP 세그먼트 데이터 번호
- 예를 들어, 1000바이트까지 정상적으로 받았다면:
- ACK# = 1001
- "나는 1000번까지 받았으니, 다음은 1001번부터 보내줘!"
Window Size(rwnd)
패킷 보내고, 이에 대한 응답을 받기 전까지 한꺼번에 보낼 수 있는 최대 크기
😳 필요한 이유?
→ ack을 보낼 때마다 받을 수 있는 빈 공간이 얼마나 되는지 알려줘야 한다.
TCP Control Field (제어 필드)

ACK (Acknowledgment, 확인)
패킷을 정상적으로 받았음을 알리는 플래그
- 성공적으로 받은 마지막 바이트의 다음 번호(현재 기다리는 번호)를 응답
- ACK 비트가 0이면 필드가 무시됨. 1이면 확인되겠죠?
📩 "나는 여기까지 받았어! 다음은 이 번호부터 보내줘!"
SYN (Synchronize Sequence Numbers, 동기화)
시퀀스 번호 동기화 및 연결 요청을 위한 플래그
✅ 역할
- TCP 연결을 시작할 때 사용됨
- SYN 비트를 1로 설정하면, 연결 요청을 의미
☎️ "나 너한테 보내고 싶은데, 연결 가능해?"
FIN (Finish, 종료)
TCP 연결을 종료하고 싶을 때 사용하는 플래그
✅ 역할
- 상대방에게 연결 종료 요청을 보냄
- 정상적인 연결 해제를 위해 사용됨
📩 "이제 볼 일 끝났어! 나 먼저 나갈게!"
TCP의 일반적인 동작 방식
양단 간 쌍방향 소통 (Normal Operation)
📩 "서로 대화하듯 주고받기!"
- TCP는 한쪽이 일방적으로 데이터를 보내는 것이 아니라,보내고-받고-확인하는 과정이 반복되는 방식
스탑 앤 웨이트 (Stop and Wait)
📩 "하나 보내고, 확인받고 다음 거 보내기!"
- 데이터를 한 번에 하나씩 보내고, 수신자의 응답(ACK)을 받은 후 다음 데이터를 전송
💡 비유: 택배 한 개씩 보내기
- 📦 A: "택배 1개 보냈어!"
- 📩 B: "받았어! 다음 거 보내!"
- 📦 A: "오케이! 그럼 2개째 보낼게!"
- (이런 식으로 하나씩 보냄)
⚠️ 단점: 이렇게 확인하는 과정이 있다보니 느릴 수 밖에 없어요. 따라서 요즘은 슬라이딩 윈도우 방식을 주로 사용합니다.
📌 신뢰할 수 있는 TCP 연결을 위한 Handshake
TCP 세그먼트는 네트워크를 통과하면서 여러 이유로 손실될 수 있습니다.

예를 들어,
- Queue가 가득 차서 패킷이 드롭되거나 (Loss)
- 전송 중 바이트가 손상될 수 있어요. (Corruption)
3-way handshake: TCP 연결 설정 과정
TCP는 신뢰할 수 있는 연결을 보장하기 위해 3-Way Handshake 과정을 거쳐 연결을 설정합니다.
실제로 데이터 전달이 시작하기 전에 한 쪽이 다른 쪽이 준비되었다는 것을 알 수 있도록 합니다.
만약 이 과정에서 오류가 나거나, 시간 초과가 발생할 경우 TCP segment를 재전송합니다. 수신자는 TCP segment를 제대로 수신하면 ACK(Positive ACKnowledge), 제대로 수신 못했으면 NACK(Negative ACKnowlegdge)를 보냅니다.
3-Way Handshake 과정 ⭐️⭐️⭐️

1️⃣ 클라이언트 → 서버 : SYN (연결 요청)
- 클라이언트가 서버에 연결 요청을 보냄
- SYN 플래그 = 1, 초기 SEQ# 설정
- 나 8000번부터 보낼거임!
2️⃣ 서버 → 클라이언트 : SYN + ACK (연결 수락 및 응답)
- 서버가 요청을 수락하고, 응답을 보냄
- 클라이언트의 SEQ# + 1 값을 ACK#로 설정
- SYN 플래그 = 1 (동기화), ACK 플래그 = 1 (확인 응답)
- 서버의 초기 SEQ#도 설정
3️⃣ 클라이언트 → 서버 : ACK (연결 확인 완료)
- 클라이언트가 서버의 응답을 확인하고 최종 ACK를 보냄
- 서버의 SEQ# + 1 값을 ACK#로 설정
⇒ 이제 데이터 송수신 가능!!
🔍 3-Way Handshake 흐름 간단 요약
단계 | 클라이언트 | 서버 | 포트 상태변화 |
---|---|---|---|
1️⃣ "서버야, 대화할래?" | SYN, SEQ# 8000 | LISTEN : 포트가 열린 상태로 연결 요청 대기 중 |
|
2️⃣ "좋아! 연결할게!" | SYN + ACK, SEQ# 15000, ACK# 8001 | SYN_RCV : SYNC 요청을 받고 상대방의 응답을 기다리는 중 |
|
3️⃣ "음음 그래그래" | ACK, SEQ# 8001, ACK# 15001 | ESTABLISHED : 포트가 연결된 상태 |
- 오케이 다음엔 8001번부터 보내주면 돼. 난 15000부터 보낸다?
4-way handshake : TCP 연결 해제 과정
TCP에서는 안정적인 연결 종료를 위해 4-Way Handshake 과정을 거칩니다.

1️⃣ 첫 번째 단계: 클라이언트 → 서버 (FIN, 연결 종료 요청)
📩 "이제 대화 끝내고 싶어!"
- 클라이언트가 연결을 종료하겠다는 FIN 플래그를 보냄
- 클라이언트는 FIN_WAIT 상태가 됨
2️⃣ 두 번째 단계: 서버 → 클라이언트 (ACK, 종료 요청 확인)
📩 "알겠어! 하지만 나 아직 할 말(보낼 데이터)이 좀 남아있어!"
- 서버가 FIN을 확인하고 ACK(확인 메시지)를 보냄
- 하지만 서버는 아직 할 말(데이터)이 남았을 수도 있으므로, CLOSE_WAIT 상태로 잠시 대기
3️⃣ 세 번째 단계: 서버 → 클라이언트 (FIN, 최종 종료 요청)
📩 "나도 이제 다 보냈어! 진짜 끝내자!"
- 서버가 모든 데이터를 전송한 후 연결 종료를 위한 FIN을 보냄
- 이때 서버는 LAST_ACK 상태가 됨
4️⃣ 네 번째 단계: 클라이언트 → 서버 (ACK, 종료 확인)
📩 "확인했어! 그럼 진짜 끝!"
- 클라이언트가 서버의 FIN을 확인하고 ACK를 보냄
- 하지만 혹시라도 남은 패킷이 있을지 몰라 잠시(TIME_WAIT 상태에서) 대기
- 일정 시간이 지나면 완전히 종료
한눈에 요약해서 보기
단계 | 클라이언트 | 서버 | 포트 상태 변화 |
---|---|---|---|
1️⃣ "이제 대화 끝내고 싶어!" | FIN 전송 | FIN_WAIT (클라이언트): 대기 상태 | |
2️⃣ "알겠어! 근데 나 아직 할 말 있어!" | ACK 전송 | CLOSE_WAIT (서버): 종료 대기 중 | |
3️⃣ "나도 이제 다 끝났어! 진짜 종료하자!" | FIN 전송 | LAST_ACK (서버): 종료 준비 중 | |
4️⃣ "확인했어! 그럼 진짜 끝!" | ACK 전송 | TIME_WAIT (클라이언트): 종료 후 대기 |
TCP 관련 질문 (심화)
왜 3단계일까??
2-Way Handshake에서는 하나의 SYN 요청, 하나의 ACK 응답만 존재한다.
- ISN 동기화가 이루어지지 않는다 (클라이언트가 서버의 ISN을 알 수 없다)
- 서버가 전송한 Segment의 순서를 구분할 수 없다.
- Pkt Loss나 Delay를 탐지할 수 없다.
- 작업 순서가 달라져 오류가 발생한다.
- 작업의 중복 수행이 발생할 수 있다.
- 서버가 전송한 Segment의 순서를 구분할 수 없다.
- “half open connection” 상황이 발생할 수 있다.
- 한 쪽 Host만 연결된 상태를 의미한다.
- 연결된 Host는 계속 자원을 낭비하게 된다.
- SYN Flooding(DoS의 일부)에 취약하다.
TCP의 연결 설정 과정(3단계)과 연결 종료 과정(4단계)이 단계가 차이나는 이유?
Client가 데이터 전송을 마쳤다고 하더라도 Server는 아직 보낼 데이터가 남아있을 수 있기 때문에 일단 FIN에 대한 ACK만 보내고, 데이터를 모두 전송한 후에 자신도 FIN 메시지를 보내기 때문이다.
초기 Sequence Number인 0부터 시작하지 않고 난수를 생성해서 설정하는 이유?
연결을 맺을 때 사용하는 포트는 유한 범위 내에서 사용하고 시간이 지남에 따라 재사용된다. 따라서 두 통신 호스트가 과거에 사용된 포트 번호 쌍을 사용하는 가능성이 존재한다.
서버 측에서는 패킷의 SYN을 보고 패킷을 구분하게 되는데 난수가 아닌 순처적인 Number가 전송된다면 이전의 Connection으로부터 오는 패킷으로 인식하는 문제가 발생할 수 있다.
이런 문제가 발생할 가능성을 줄이기 위해서 난수로 ISN을 설정한다.
Half-Close 기법은 왜 필요할까?
연결을 종료하려고 할 때 완전히 종료하지 않고 반만 종료한다.
- Half-Close 기법을 사용하면 종료 요청자가 처음 보내는 FIN 패킷에 승인 번호를 함께 담아서 보내게 되는데, 이때 승인 번호의 의미는 "일단 연결은 종료할건데 귀는 열어둘게. 이 승인 번호까지 처리했으니까 더 보낼 거 있으면 보내"라는 뜻이다.
- 이후 수신자가 남은 데이터를 모두 보내고 나면 다시 요청자에게 FIN 패킷을 보냄으로써 모든 데이터가 처리되었다는 신호 (3) FIN를 보낸다. 그럼 요청자는 그때 나머지 반을 닫으면서 좀 더 안전하게 연결을 종료할 수 있게 된다.
만약 Server에서 FIN 플래그를 전송하기 전에 전송한 패킷이 Routing 지연이나 패킷 유실로 인한 재전송 등으로 인해 FIN 패킷보다 늦게 도착하는 상황이 발생하면 어떻게 될까?
이러한 현상에 대비하여 Client는 Server로부터 FIN 플래그를 수신하더라도 일정시간(Default: 240sec)동안 세션을 남겨 놓고 잉여 패킷을 기다리는 과정을 거친다. (TIME_WAIT 과정)
캡슐화와 역캡슐화

인터넷에서 TCP/IP 연결을 통해 데이터가 전송되는 과정을 살펴봅시다.
패킷의 송수신 과정 중 송신 과정에서는 캡슐화가, 수신 과정에서는 역캡슐화가 이루어집니다.
캡슐화 - 보낼때
우선 송신 측 컴퓨터에서 웹사이트에 접속하려고 하면, 1번 응용계층에서는 웹 사이트를 접속하기 위한 “요청 데이터”가 만들어진다.
해당 데이터는 2번의 전송 계층에 전달되는데, 전송 계층에서 신뢰할 수 있는 통신이 이루어지도록 응용계층에서 만들어진 데이터에 헤더를 붙인다. 이런식으로 전송 계층 헤더, 데이터 링크 계층 헤더와 트레일러가 추가 되었다. 이처럼 필요한 데이터를 추가해 나가는 것을 “캡슐화”라고 합니다.
데이터가 각 계층을 지날 때마다 데이터가 캡슐화되어 하위 계층으로 이동합니다. 최하위 계층(물리)에서는 이 디지털 데이터를 전기 신호로 변환하여 전송 매체를 통해 라우터 등의 중간 노드를 거쳐 수신 호스트의 최하위 계층인 네트워크 인터페이스 계층으로 전송합니다.
역캡슐화 - 받을때
수신 호스트의 각 계층에서는 하위 계층으로부터 받은 데이터에 포함된 헤더 부분의 정보를 사용해서 해당 계층의 프로토콜을 처리한 후 헤더부분을 제거한 데이터를 상위 계층으로 넘깁니다.
단계를 거칠때마다 붙였던 헤더가 사라지겠져? 그럼 최상위 계층에서 남는건 뭘까요?
바로 페이로드, 즉 송신자가 보내려고 했던 데이터가 남게됩니다.
🎁 마치 선물 포장과 같다고 생각하면 쉬워요!
- 캡슐화: 친구에게 줄 선물을 예쁘게 포장하는 것. 이렇게 하면 내용물이 드러나지 않고, 안전하게 전달될 수 있어요. 데이터를 보낼때 안에 있는게 보이면 안되겠죠? 그러니까 감싸서 캡슐로 만들어서 보내는거!
- 역캡슐화: 친구가 포장을 열어 내용을 확인하는 것. 받는사람은 포장을 뜯어야만 선물의 내용을 알 수 있게 됩니다. 즉 포장지를 벗기듯이 캡슐을 뜯어보면 원래 친구가 보내려고 했던 데이터가 나오겠죠?
⇒ 이처럼, 캡슐화는 데이터를 숨기는 것이고, 역캡슐화는 숨겨진 데이터를 확인하는 과정입니다! 객체지향의 은닉과 비슷한 개념이라고 보시면 됩니다!
TCP의 3가지 핵심 제어 기능
TCP는 데이터를 안정적이고 효율적으로 주고받기 위해 다음 3가지 기능을 사용합니다!
window 크기 = 단위 시간 내에 보내는 패킷의 수
흐름 제어 (Flow Control)
📩 "천천히! 너무 많이 보내지 마!"
데이터 수신자가 처리할 수 있는 만큼만 보내도록 조절하는 기능
💡 물컵에 물 붓기
- 컵(수신자)은 작은데 물(데이터)을 너무 많이 부으면 넘쳐버림.
- TCP는 "조금만 줘! 아직 처리 중이야!" 라고 조절해줌.
- 대표적인 방식: 슬라이딩 윈도우(Sliding Window)
- 한 번에 여러 개의 데이터를 보내고, 받은 만큼만 윈도우를 이동시켜 전송 속도를 높이는 방식
🛠 예시
- 송신자 → 수신자: "데이터 100개 보낼게!"
- 수신자 → 송신자: "나 지금 50개밖에 못 받아! 천천히!"
- 송신자: "오케이! 50개만 보낼게!"
혼잡 제어 (Congestion Control)
📩 "교통 체증 줄여야 해!"
네트워크가 너무 바빠서 막히지 않도록 데이터 전송 속도를 조절하는 기능
💡 도로에서 차 막히는 상황 🚗🚦
- 차(데이터)가 너무 많으면 도로(네트워크)가 막힘
- TCP는 "차가 많네? 속도 줄여!" 하면서 막히지 않도록 조절
- 대표적인 방식
- 슬로우 스타트(Slow Start)
- 처음에는 데이터를 천천히 보내다가, 네트워크가 괜찮으면 점점 더 빠르게 보냄
- AIMD(첨가적 증가 & 다중적 감소)
- 처음에 패킷을 하나씩 보내고 이것이 문제없이 도착하면 window를 1씩 증가시켜가며 전송하는 방법
- 패킷 전송에 실패하거나 일정 시간을 넘으면 패킷의 보내는 속도를 절반으로 줄인다.
- 슬로우 스타트(Slow Start)
🛠 예시
- 송신자 → 네트워크: "데이터 100개 보낼게!"
- 네트워크: "헉! 너무 많아! 좀 버릴게!" (손실 발생)
- 송신자: "아, 미안! 속도 줄일게!" (조절)
- 네트워크가 원활해지면 다시 속도 올림 ⇒ 고속도로에선 달려잇~~
오류 제어 (Error Control)
📩 "잘못된 데이터 다시 보내줘!"
데이터가 손상되거나 손실되었을 때 다시 요청하는 기능
💡 비유: 택배 배송 중 박스가 찌그러진 상황 📦
- 택배(데이터)를 받았는데 찌그러졌거나 일부 빠져있음
- 수신자는 "이거 잘못 왔어! 다시 보내줘!" 라고 요청
- 대표적인 방식
- ACK
- 못받았으면 못받은데부터 다시 보내달라고 요청
- 빠른 재전송(Fast Retransmit)
- 데이터가 중간에 손실되었을 때, 기다리지 않고 바로 다시 보내는 방법
저기요 배달 잘못 보내셨어요!!
⇒아하 다시 보내드릴게요
이런 느낌
- ACK
🛠 예시
- 송신자 → 수신자: "데이터 100개 보낼게!"
- 수신자: "90개는 잘 왔는데 10개는 이상해! 다시 보내줘!"
- 송신자: "오케이! 10개 다시 보낼게!"
주요 기능 요약
기능 | 역할 | 쉬운 비유 | 관련 개념 |
---|---|---|---|
흐름 제어 | 수신자가 감당할 수 있는 속도로 조절 | 컵에 물 붓기 ☕ | 슬라이딩 윈도우 |
혼잡 제어 | 네트워크가 막히지 않도록 조절 | 도로 교통 체증 🚗 | 슬로우 스타트 |
오류 제어 | 손상된 데이터 다시 요청 | 찌그러진 택배 교환 📦 | 빠른 재전송 |
양단 간 소통 | 서로 대화하듯 데이터 주고받기 | 대화하는 친구들 🗣️ | - |
스탑 앤 웨이트 | 하나 보내고, 응답 받고, 다음 거 보내기 | 택배 한 개씩 보내기 📦 | - |
참고 자료
모든 자료는 개인적인 공부 목적으로 사용했습니다.
- https://velog.io/@moonlt93/캡슐화-역캡슐화-encapsulation-decapsulationhttps://wjdtn7823.tistory.com/37
- https://velog.io/@averycode/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-TCPUDP%EC%99%80-3-Way-Handshake4-Way-Handshake
- https://velog.io/@hidaehyunlee/TCP-%EC%99%80-UDP-%EC%9D%98-%EC%B0%A8%EC%9D%B4
- https://inpa.tistory.com/entry/WEB-🌐-포트-란-무엇인가
'CS > Network' 카테고리의 다른 글
[네트워크] NAT (0) | 2025.01.29 |
---|---|
[네트워크] 클래스 기반 주소 지정 (0) | 2025.01.29 |
[네트워크] IP 주소 개요 (0) | 2025.01.29 |
[네트워크] 소켓 프로그래밍: 프로토콜, 클라이언트와 서버의 함수호출 (0) | 2025.01.29 |
[네트워크] 소켓 프로그래밍 개요 (0) | 2025.01.29 |