🌐 OSI 7계층 모델 완벽 가이드
Backend 개발자가 알아야 할 네트워크 계층 구조
💡 왜 계층 모델이 필요한가?
문제: 네트워크는 복잡하다!
- 다양한 하드웨어
- 다양한 프로토콜
- 다양한 응용 프로그램
해결: 계층으로 나누어 관리!
복잡한 시스템 → 7개 계층으로 분할 → 각 계층은 독립적 기능
📊 OSI 7계층 개요
계층 구조
┌─────────────────────────────────────┐
│ 7. 응용 계층 (Application) │ ← 사용자 인터페이스
├─────────────────────────────────────┤
│ 6. 표현 계층 (Presentation) │ ← 데이터 형식 변환
├─────────────────────────────────────┤
│ 5. 세션 계층 (Session) │ ← 연결 관리
├─────────────────────────────────────┤
│ 4. 전송 계층 (Transport) │ ← 신뢰성 있는 전송 (TCP/UDP)
├─────────────────────────────────────┤
│ 3. 네트워크 계층 (Network) │ ← 경로 선택 (IP)
├─────────────────────────────────────┤
│ 2. 데이터 링크 계층 (Data Link) │ ← 물리적 주소 지정 (MAC)
├─────────────────────────────────────┤
│ 1. 물리 계층 (Physical) │ ← 전기 신호
└─────────────────────────────────────┘
기억법
Application - All
Presentation - People
Session - Seem
Transport - To
Network - Need
Data Link - Data
Physical - Processing
🔍 각 계층 상세 설명
1️⃣ 물리 계층 (Physical Layer)
역할: 비트를 전기 신호로 변환하여 전송
주요 장비:
- 케이블 (UTP, 광섬유)
- 리피터
- 허브
Backend 개발자 관점:
거의 신경 쓸 일 없음
하드웨어 엔지니어 영역
실무 예시:
- 서버실 네트워크 케이블 연결
- 10Gbps vs 1Gbps 네트워크 카드
2️⃣ 데이터 링크 계층 (Data Link Layer)
역할: 물리적 주소(MAC)를 이용한 노드 간 전송
주요 프로토콜:
- Ethernet
- Wi-Fi (802.11)
- PPP
주요 장비:
- 스위치
- 브리지
Backend 개발자 관점:
// MAC 주소 확인
InetAddress localhost = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(localhost);
byte[] mac = network.getHardwareAddress();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
System.out.println("MAC Address: " + sb.toString());
// 출력: MAC Address: 00-1A-2B-3C-4D-5E
실무 예시:
- 같은 네트워크(LAN) 내 통신
- ARP 테이블 확인
3️⃣ 네트워크 계층 (Network Layer)
역할: IP 주소를 이용한 경로 선택 (라우팅)
주요 프로토콜:
- IP (Internet Protocol) ⭐
- ICMP (ping)
- ARP
주요 장비:
- 라우터
Backend 개발자 관점:
// IP 주소 얻기
InetAddress localhost = InetAddress.getLocalHost();
System.out.println("IP: " + localhost.getHostAddress());
// 출력: IP: 192.168.0.10
// 특정 호스트의 IP 조회
InetAddress google = InetAddress.getByName("google.com");
System.out.println("Google IP: " + google.getHostAddress());
// 출력: Google IP: 142.250.196.46
// 연결 가능 여부 확인 (ICMP)
boolean reachable = google.isReachable(5000);
System.out.println("Reachable: " + reachable);
실무 예시:
# IP 확인
ifconfig # Mac/Linux
ipconfig # Windows
# 라우팅 경로 확인
traceroute google.com # Mac/Linux
tracert google.com # Windows
# Ping 테스트
ping 8.8.8.8
4️⃣ 전송 계층 (Transport Layer) ⭐⭐⭐
역할: 프로세스 간 신뢰성 있는 데이터 전송
주요 프로토콜:
- TCP (Transmission Control Protocol) ⭐
- UDP (User Datagram Protocol) ⭐
TCP vs UDP 비교
| 특성 | TCP | UDP |
|---|---|---|
| 연결 방식 | 연결 지향 (Connection-oriented) | 비연결 (Connectionless) |
| 신뢰성 | ✅ 보장 (재전송, 순서 보장) | ❌ 미보장 |
| 속도 | 느림 | 빠름 |
| 용도 | HTTP, HTTPS, FTP, SMTP | DNS, 스트리밍, 게임 |
| 헤더 크기 | 20 bytes | 8 bytes |
| 흐름 제어 | ✅ 있음 | ❌ 없음 |
| 혼잡 제어 | ✅ 있음 | ❌ 없음 |
TCP 3-Way Handshake
클라이언트 서버
│ │
│─────── SYN ─────────>│ 1. 연결 요청
│ │
│<────── SYN+ACK ──────│ 2. 요청 수락
│ │
│─────── ACK ─────────>│ 3. 연결 확립
│ │
│ 데이터 전송 시작 │
Backend 개발자 관점
// TCP 소켓 (연결 지향)
@Service
public class TcpClientService {
public String sendTcpRequest(String host, int port, String message)
throws IOException {
// 1. 소켓 생성 및 연결 (3-Way Handshake)
try (Socket socket = new Socket(host, port);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
// 2. 데이터 전송
out.println(message);
// 3. 응답 수신
return in.readLine();
}
}
}
// UDP 소켓 (비연결)
@Service
public class UdpClientService {
public void sendUdpRequest(String host, int port, String message)
throws IOException {
try (DatagramSocket socket = new DatagramSocket()) {
InetAddress address = InetAddress.getByName(host);
byte[] buffer = message.getBytes();
// 데이터그램 생성 및 전송 (연결 없이 바로 전송)
DatagramPacket packet = new DatagramPacket(
buffer, buffer.length, address, port
);
socket.send(packet);
}
}
}
Spring Boot에서의 TCP
@RestController
@RequestMapping("/api")
public class ApiController {
// HTTP는 TCP 위에서 동작
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody UserRequest request) {
// 클라이언트 ↔ 서버: TCP 연결
// HTTP 요청/응답: TCP를 통해 전송
User user = userService.create(request);
return ResponseEntity.ok(user);
}
}
5️⃣ 세션 계층 (Session Layer)
역할: 통신 세션 관리
Backend 개발자 관점:
@Controller
public class LoginController {
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password,
HttpSession session) { // 세션 계층
if (authService.authenticate(username, password)) {
// 세션 생성 및 유지
session.setAttribute("user", username);
session.setMaxInactiveInterval(1800); // 30분
return "redirect:/dashboard";
}
return "login";
}
@GetMapping("/dashboard")
public String dashboard(HttpSession session) {
// 세션 확인
String user = (String) session.getAttribute("user");
if (user == null) {
return "redirect:/login";
}
return "dashboard";
}
@PostMapping("/logout")
public String logout(HttpSession session) {
// 세션 종료
session.invalidate();
return "redirect:/login";
}
}
실무 예시:
- HTTP 세션 관리
- WebSocket 연결 유지
- FTP 파일 전송 재개
6️⃣ 표현 계층 (Presentation Layer)
역할: 데이터 형식 변환, 암호화, 압축
Backend 개발자 관점:
// 1. 데이터 직렬화/역직렬화
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<User> createUser(
@RequestBody User user // JSON → Java Object (역직렬화)
) {
User created = userService.create(user);
return ResponseEntity.ok(created); // Java Object → JSON (직렬화)
}
}
// 2. 암호화
@Service
public class EncryptionService {
private static final String ALGORITHM = "AES";
public String encrypt(String data, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
public String decrypt(String encryptedData, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decoded = Base64.getDecoder().decode(encryptedData);
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted);
}
}
// 3. 압축
@Service
public class CompressionService {
public byte[] compress(String data) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzipOS = new GZIPOutputStream(baos)) {
gzipOS.write(data.getBytes(StandardCharsets.UTF_8));
}
return baos.toByteArray();
}
public String decompress(byte[] compressed) throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
try (GZIPInputStream gzipIS = new GZIPInputStream(bais);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = gzipIS.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
return baos.toString(StandardCharsets.UTF_8);
}
}
}
7️⃣ 응용 계층 (Application Layer) ⭐⭐⭐
역할: 사용자 애플리케이션에 네트워크 서비스 제공
주요 프로토콜:
- HTTP/HTTPS (웹)
- FTP (파일 전송)
- SMTP (이메일 송신)
- POP3/IMAP (이메일 수신)
- DNS (도메인 이름 해석)
- SSH (원격 접속)
HTTP 프로토콜
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductService productService;
// GET 요청 (조회)
@GetMapping("/{id}")
public ResponseEntity<Product> getProduct(@PathVariable Long id) {
Product product = productService.findById(id);
return ResponseEntity.ok(product);
}
// POST 요청 (생성)
@PostMapping
public ResponseEntity<Product> createProduct(
@RequestBody ProductRequest request
) {
Product product = productService.create(request);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(product);
}
// PUT 요청 (수정)
@PutMapping("/{id}")
public ResponseEntity<Product> updateProduct(
@PathVariable Long id,
@RequestBody ProductRequest request
) {
Product product = productService.update(id, request);
return ResponseEntity.ok(product);
}
// DELETE 요청 (삭제)
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
productService.delete(id);
return ResponseEntity.noContent().build();
}
}
DNS 조회
@Service
public class DnsService {
public String resolveHostname(String hostname) {
try {
InetAddress address = InetAddress.getByName(hostname);
return address.getHostAddress();
} catch (UnknownHostException e) {
throw new RuntimeException("Cannot resolve: " + hostname, e);
}
}
public List<String> getAllIpAddresses(String hostname) {
try {
InetAddress[] addresses = InetAddress.getAllByName(hostname);
return Arrays.stream(addresses)
.map(InetAddress::getHostAddress)
.collect(Collectors.toList());
} catch (UnknownHostException e) {
throw new RuntimeException("Cannot resolve: " + hostname, e);
}
}
}
🌐 TCP/IP 프로토콜 스택 (인터넷 모델)
OSI 7계층 vs TCP/IP 4계층
OSI 7계층 TCP/IP 4계층
┌─────────────────┐
│ 7. 응용 계층 │
├─────────────────┤ ┌─────────────────┐
│ 6. 표현 계층 │ │ 4. 응용 계층 │
├─────────────────┤ → │ (Application) │
│ 5. 세션 계층 │ └─────────────────┘
├─────────────────┤ ┌─────────────────┐
│ 4. 전송 계층 │ → │ 3. 전송 계층 │
├─────────────────┤ │ (Transport) │
│ 3. 네트워크 계층 │ → └─────────────────┘
├─────────────────┤ ┌─────────────────┐
│ 2. 데이터 링크 │ → │ 2. 인터넷 계층 │
├─────────────────┤ │ (Internet) │
│ 1. 물리 계층 │ └─────────────────┘
└─────────────────┘ ┌─────────────────┐
│ 1. 네트워크 │
│ 접근 계층 │
│ (Network Access)│
└─────────────────┘
실무에서 사용하는 모델
TCP/IP 4계층이 실무 표준!
응용 계층: HTTP, FTP, SMTP, DNS
전송 계층: TCP, UDP
인터넷 계층: IP, ICMP, ARP
네트워크 접근: Ethernet, Wi-Fi
🔧 데이터 전송 과정
캡슐화 (Encapsulation)
송신 측 (데이터 생성)
┌─────────────────────────────────────────┐
│ 7. 응용: Data │
├─────────────────────────────────────────┤
│ 4. 전송: TCP Header + Data │ ← Segment
├─────────────────────────────────────────┤
│ 3. 네트워크: IP Header + Segment │ ← Packet
├─────────────────────────────────────────┤
│ 2. 데이터 링크: Frame Header + Packet + CRC│ ← Frame
└─────────────────────────────────────────┘
↓
전송 매체 (케이블, 무선)
역캡슐화 (Decapsulation)
수신 측 (데이터 수신)
┌─────────────────────────────────────────┐
│ 2. 데이터 링크: Frame 검증 및 헤더 제거 │
├─────────────────────────────────────────┤
│ 3. 네트워크: IP Header 확인 및 제거 │
├─────────────────────────────────────────┤
│ 4. 전송: TCP Header 확인 및 제거 │
├─────────────────────────────────────────┤
│ 7. 응용: Data 전달 │
└─────────────────────────────────────────┘
실제 HTTP 요청 예시
7. 응용 계층
┌───────────────────────────────────┐
│ GET /api/users/1 HTTP/1.1 │
│ Host: example.com │
│ Accept: application/json │
└───────────────────────────────────┘
↓
4. 전송 계층 (TCP)
┌───────────────────────────────────┐
│ TCP Header (Port: 80) │
│ + HTTP Request │
└───────────────────────────────────┘
↓
3. 네트워크 계층 (IP)
┌───────────────────────────────────┐
│ IP Header (Dest: 93.184.216.34) │
│ + TCP Segment │
└───────────────────────────────────┘
↓
2. 데이터 링크 계층 (Ethernet)
┌───────────────────────────────────┐
│ Ethernet Header (MAC Address) │
│ + IP Packet │
│ + CRC │
└───────────────────────────────────┘
🛠️ 실무 디버깅 & 트러블슈팅
계층별 문제 진단
| 계층 | 문제 증상 | 확인 방법 | 해결 방법 |
|---|---|---|---|
| 7. 응용 | 404, 500 에러 | 로그 확인, Postman | 코드 수정 |
| 4. 전송 | 타임아웃 | netstat, ss | 방화벽, 포트 확인 |
| 3. 네트워크 | 연결 안 됨 | ping, traceroute | 라우팅 확인 |
| 2. 데이터 링크 | 네트워크 느림 | arp -a | 스위치, 케이블 점검 |
| 1. 물리 | 연결 끊김 | 케이블 확인 | 케이블 교체 |
유용한 명령어
# 1. 네트워크 연결 확인 (계층 3)
ping google.com
# 2. 라우팅 경로 확인 (계층 3)
traceroute google.com
# 3. 포트 열림 확인 (계층 4)
telnet example.com 80
nc -zv example.com 80
# 4. 연결된 소켓 확인 (계층 4)
netstat -an | grep ESTABLISHED
ss -tuln
# 5. DNS 조회 (계층 7)
nslookup google.com
dig google.com
# 6. HTTP 요청 테스트 (계층 7)
curl -v https://api.example.com/users
Spring Boot 로깅
# application.yml
logging:
level:
org.springframework.web: DEBUG
org.apache.http: DEBUG
org.apache.http.wire: DEBUG
@Slf4j
@RestController
public class ApiController {
@GetMapping("/test")
public String test(HttpServletRequest request) {
// 요청 정보 로깅 (계층 7)
log.info("Method: {}", request.getMethod());
log.info("URI: {}", request.getRequestURI());
log.info("Remote IP: {}", request.getRemoteAddr());
log.info("Remote Port: {}", request.getRemotePort());
return "OK";
}
}
🎯 실무 시나리오
시나리오 1: HTTP 요청 전체 과정
사용자: https://api.example.com/users/1 접속
1. DNS 조회 (계층 7)
- api.example.com → 93.184.216.34
2. TCP 연결 (계층 4)
- 3-Way Handshake
- 클라이언트 포트: 54321
- 서버 포트: 443 (HTTPS)
3. TLS 핸드셰이크 (계층 6)
- 인증서 검증
- 암호화 키 교환
4. HTTP 요청 전송 (계층 7)
GET /users/1 HTTP/1.1
Host: api.example.com
5. 라우팅 (계층 3)
- 클라이언트 → 라우터 → 인터넷 → 서버
6. 서버 처리
- Controller → Service → Repository → DB
- 응답 생성
7. HTTP 응답 수신 (계층 7)
HTTP/1.1 200 OK
Content-Type: application/json
{"id": 1, "name": "홍길동"}
8. TCP 연결 종료 (계층 4)
- 4-Way Handshake
시나리오 2: 타임아웃 문제 해결
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
// 계층 4: TCP 타임아웃 설정
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 연결 타임아웃: 5초
factory.setReadTimeout(10000); // 읽기 타임아웃: 10초
return new RestTemplate(factory);
}
}
@Service
@Slf4j
public class ExternalApiService {
private final RestTemplate restTemplate;
public UserResponse getUser(Long id) {
String url = "https://api.example.com/users/" + id;
try {
// 계층 7: HTTP 요청
return restTemplate.getForObject(url, UserResponse.class);
} catch (ResourceAccessException e) {
// 계층 4: 타임아웃 또는 연결 실패
log.error("Connection timeout or refused: {}", url, e);
throw new ExternalApiException("External API unavailable", e);
} catch (HttpClientErrorException e) {
// 계층 7: HTTP 4xx 에러
log.error("Client error: {} - {}", e.getStatusCode(), url, e);
throw new ExternalApiException("Invalid request", e);
} catch (HttpServerErrorException e) {
// 계층 7: HTTP 5xx 에러
log.error("Server error: {} - {}", e.getStatusCode(), url, e);
throw new ExternalApiException("Server error", e);
}
}
}
📚 핵심 요약
Backend 개발자가 중점적으로 알아야 할 계층
| 계층 | 중요도 | 이유 |
|---|---|---|
| 7. 응용 | ⭐⭐⭐ | HTTP, REST API 설계 |
| 4. 전송 | ⭐⭐⭐ | TCP/UDP, 소켓 프로그래밍 |
| 3. 네트워크 | ⭐⭐ | IP 주소, 라우팅 이해 |
| 6, 5, 2, 1 | ⭐ | 기본 개념만 이해 |
프로토콜 선택 가이드
신뢰성 필요 + 순서 보장 → TCP
- HTTP, HTTPS, FTP, SMTP, SSH
속도 중요 + 손실 허용 → UDP
- DNS, 스트리밍, 게임, VoIP
데이터 단위
7. 응용: Data (데이터)
4. 전송: Segment (세그먼트)
3. 네트워크: Packet (패킷)
2. 데이터 링크: Frame (프레임)
1. 물리: Bit (비트)
💡 실무 Best Practices
1️⃣ 타임아웃 설정
// ✅ 항상 타임아웃 설정
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory =
new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(5000);
factory.setReadTimeout(10000);
return new RestTemplate(factory);
}
// ❌ 타임아웃 미설정 (무한 대기 가능)
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
2️⃣ 재시도 로직
@Service
public class ResilientApiService {
private final RestTemplate restTemplate;
@Retryable(
value = {ResourceAccessException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000)
)
public UserResponse getUser(Long id) {
return restTemplate.getForObject(
"https://api.example.com/users/" + id,
UserResponse.class
);
}
}
3️⃣ 연결 풀 관리
@Configuration
public class HttpClientConfig {
@Bean
public HttpClient httpClient() {
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100); // 최대 연결 수
connectionManager.setDefaultMaxPerRoute(20); // 호스트당 최대 연결
return HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
}
}
🚀 마무리
"OSI 7계층 모델은 네트워크의 언어입니다. 각 계층을 이해하면 문제 해결이 쉬워집니다."
Backend 개발자라면:
- 🌐 응용 계층: HTTP, REST API 마스터
- 🔌 전송 계층: TCP/UDP 차이 이해
- 🗺️ 네트워크 계층: IP 주소, 라우팅 기본
- 🛠️ 디버깅: 계층별 문제 진단 능력
계층 모델을 이해하면 네트워크 문제를 체계적으로 접근할 수 있습니다! 💪