포스트

[CS 기초 #5] 네트워크: OSI 7계층과 TCP/IP 완벽 이해

[CS 기초 #5] 네트워크: OSI 7계층과 TCP/IP 완벽 이해

네트워크의 기본 원리를 배워봅시다! 브라우저에 URL을 입력하면 전 세계를 거쳐 데이터가 도착합니다. OSI 7계층과 TCP/IP의 마법을 이해해봅시다.

🎯 이 글을 읽고 나면

  • OSI 7계층 모델과 각 계층의 역할을 설명할 수 있습니다
  • TCP와 UDP의 차이점을 이해합니다
  • HTTP/HTTPS와 DNS의 동작 원리를 알게 됩니다
  • IP 주소, 서브넷, 라우팅 개념을 파악합니다
  • 네트워크 보안 기초를 학습합니다

📚 사전 지식

  • 기본 인터넷 사용: 웹 브라우징, 이메일 정도면 충분합니다
  • 컴퓨터 구조: 이전 글: 컴퓨터 구조 참고
  • 프로그래밍 경험: 어떤 언어든 괜찮습니다

💡 핵심 개념 미리보기

네트워크는 컴퓨터들이 데이터를 주고받기 위한 체계입니다. OSI 7계층은 네트워크를 7개 논리적 계층으로 나눈 표준 모델이고, TCP/IP는 실제 인터넷에서 사용하는 4계층 프로토콜입니다. 데이터는 패킷으로 나뉘어 라우터를 거쳐 목적지로 전달되며, TCP는 신뢰성 있는 전송을, UDP는 빠른 전송을 담당합니다!


🌐 들어가며: 인터넷은 어떻게 동작하는가?

브라우저에 URL을 입력하면 어떤 일이 일어날까요? 전 세계 컴퓨터가 어떻게 서로 통신할 수 있을까요?

오늘은 인터넷의 기반이 되는 네트워크 프로토콜OSI 7계층, TCP/IP 등 네트워크의 핵심 개념을 알아보겠습니다. 이 지식은 웹 개발, 클라우드 아키텍처, 보안의 기초가 됩니다!

📡 네트워크의 기본 개념

네트워크 구성 요소

graph TB
    subgraph "네트워크 구성"
        PC1[PC] --> Switch[스위치]
        PC2[PC] --> Switch
        Switch --> Router[라우터]
        Router --> Internet[인터넷]
        
        Server[서버] --> Switch2[스위치]
        Switch2 --> Router2[라우터]
        Router2 --> Internet
    end
    
    subgraph "통신 과정"
        A[송신자] --> B[패킷 생성]
        B --> C[라우팅]
        C --> D[전송]
        D --> E[수신자]
    end

IP 주소와 포트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import socket
import struct

class NetworkBasics:
    """네트워크 기본 개념 시연"""
    
    @staticmethod
    def ip_to_binary(ip_address):
        """IP 주소를 이진수로 변환"""
        octets = ip_address.split('.')
        binary_octets = [format(int(octet), '08b') for octet in octets]
        return '.'.join(binary_octets)
    
    @staticmethod
    def subnet_mask_info(ip_address, subnet_mask):
        """서브넷 정보 계산"""
        # IP를 정수로 변환
        ip_int = struct.unpack('>I', socket.inet_aton(ip_address))[0]
        mask_int = struct.unpack('>I', socket.inet_aton(subnet_mask))[0]
        
        # 네트워크 주소
        network = ip_int & mask_int
        network_addr = socket.inet_ntoa(struct.pack('>I', network))
        
        # 브로드캐스트 주소
        broadcast = network | ~mask_int & 0xFFFFFFFF
        broadcast_addr = socket.inet_ntoa(struct.pack('>I', broadcast))
        
        # 호스트 수
        host_bits = 32 - bin(mask_int).count('1')
        max_hosts = 2 ** host_bits - 2  # 네트워크와 브로드캐스트 제외
        
        return {
            'network': network_addr,
            'broadcast': broadcast_addr,
            'max_hosts': max_hosts
        }
    
    @staticmethod
    def port_categories():
        """포트 번호 분류"""
        return {
            'Well-known Ports': (0, 1023),
            'Registered Ports': (1024, 49151),
            'Dynamic/Private Ports': (49152, 65535),
            'Common Services': {
                'HTTP': 80,
                'HTTPS': 443,
                'FTP': 21,
                'SSH': 22,
                'SMTP': 25,
                'DNS': 53,
                'MySQL': 3306,
                'PostgreSQL': 5432
            }
        }

# 네트워크 기본 개념 테스트
nb = NetworkBasics()

# IP 주소 이진 변환
ip = "192.168.1.100"
print(f"IP 주소: {ip}")
print(f"이진수: {nb.ip_to_binary(ip)}")

# 서브넷 정보
subnet_info = nb.subnet_mask_info("192.168.1.100", "255.255.255.0")
print(f"\n서브넷 정보:")
print(f"네트워크 주소: {subnet_info['network']}")
print(f"브로드캐스트 주소: {subnet_info['broadcast']}")
print(f"최대 호스트 수: {subnet_info['max_hosts']}")

# 포트 정보
port_info = nb.port_categories()
print(f"\n주요 서비스 포트:")
for service, port in port_info['Common Services'].items():
    print(f"  {service}: {port}")

🏗️ OSI 7계층 모델

OSI(Open Systems Interconnection) 모델은 네트워크 통신을 7개 계층으로 나눈 표준 모델입니다.

graph TD
    subgraph "OSI 7계층"
        L7[7. Application<br/>응용 계층<br/>HTTP, FTP, SMTP]
        L6[6. Presentation<br/>표현 계층<br/>암호화, 압축]
        L5[5. Session<br/>세션 계층<br/>연결 관리]
        L4[4. Transport<br/>전송 계층<br/>TCP, UDP]
        L3[3. Network<br/>네트워크 계층<br/>IP, 라우팅]
        L2[2. Data Link<br/>데이터링크 계층<br/>이더넷, 스위치]
        L1[1. Physical<br/>물리 계층<br/>케이블, 허브]
        
        L7 --> L6
        L6 --> L5
        L5 --> L4
        L4 --> L3
        L3 --> L2
        L2 --> L1
    end
    
    subgraph "데이터 캡슐화"
        Data[데이터]
        Segment[세그먼트]
        Packet[패킷]
        Frame[프레임]
        Bits[비트]
        
        Data --> Segment
        Segment --> Packet
        Packet --> Frame
        Frame --> Bits
    end

각 계층의 역할과 프로토콜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class OSIModel:
    """OSI 7계층 모델 시뮬레이션"""
    
    def __init__(self):
        self.layers = {
            7: {'name': 'Application', 'protocols': ['HTTP', 'HTTPS', 'FTP', 'SMTP', 'DNS']},
            6: {'name': 'Presentation', 'functions': ['암호화', '압축', '인코딩']},
            5: {'name': 'Session', 'functions': ['세션 설정', '유지', '종료']},
            4: {'name': 'Transport', 'protocols': ['TCP', 'UDP']},
            3: {'name': 'Network', 'protocols': ['IP', 'ICMP', 'ARP']},
            2: {'name': 'Data Link', 'protocols': ['Ethernet', 'PPP', 'Wi-Fi']},
            1: {'name': 'Physical', 'components': ['케이블', '허브', '리피터']}
        }
    
    def encapsulation(self, data):
        """데이터 캡슐화 과정"""
        encapsulated = data
        headers = []
        
        # 각 계층을 거치며 헤더 추가
        for layer in range(7, 0, -1):
            layer_name = self.layers[layer]['name']
            
            if layer == 7:  # Application
                headers.append(f"[HTTP Header]")
            elif layer == 4:  # Transport
                headers.append(f"[TCP Header: Port, Seq#]")
            elif layer == 3:  # Network
                headers.append(f"[IP Header: Src IP, Dst IP]")
            elif layer == 2:  # Data Link
                headers.append(f"[Ethernet Header: MAC]")
            
            if headers and layer <= 4:
                encapsulated = f"{headers[-1]} {encapsulated}"
            
            print(f"Layer {layer} ({layer_name}): {encapsulated}")
        
        return encapsulated
    
    def decapsulation(self, frame):
        """데이터 디캡슐화 과정"""
        print("\n디캡슐화 과정:")
        layers_data = [
            "[Ethernet Header: MAC]",
            "[IP Header: Src IP, Dst IP]",
            "[TCP Header: Port, Seq#]",
            "[HTTP Header]"
        ]
        
        current = frame
        for layer in range(1, 8):
            layer_name = self.layers[layer]['name']
            
            if layer <= 4 and layers_data:
                header = layers_data.pop(0)
                current = current.replace(header + " ", "")
            
            print(f"Layer {layer} ({layer_name}): {current}")
        
        return current

# OSI 모델 시연
osi = OSIModel()
print("데이터 캡슐화 과정:")
print("=" * 60)
original_data = "Hello, World!"
frame = osi.encapsulation(original_data)

print("\n" + "=" * 60)
osi.decapsulation(frame)

🔗 TCP/IP 프로토콜 스택

TCP/IP는 인터넷의 기반이 되는 프로토콜 스위트입니다.

TCP vs UDP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import time
import random

class TCPSimulator:
    """TCP 통신 시뮬레이션"""
    
    def __init__(self):
        self.seq_num = 0
        self.ack_num = 0
        self.window_size = 5
        self.congestion_window = 1
        
    def three_way_handshake(self):
        """TCP 3-way handshake"""
        print("TCP 3-Way Handshake:")
        print("-" * 40)
        
        # SYN
        self.seq_num = random.randint(1000, 9999)
        print(f"1. Client → Server: SYN (SEQ={self.seq_num})")
        
        # SYN-ACK
        server_seq = random.randint(1000, 9999)
        self.ack_num = self.seq_num + 1
        print(f"2. Server → Client: SYN-ACK (SEQ={server_seq}, ACK={self.ack_num})")
        
        # ACK
        self.seq_num = self.ack_num
        self.ack_num = server_seq + 1
        print(f"3. Client → Server: ACK (SEQ={self.seq_num}, ACK={self.ack_num})")
        print("연결 설정 완료!\n")
        
        return True
    
    def send_with_flow_control(self, data_segments):
        """흐름 제어를 포함한 데이터 전송"""
        print("TCP 데이터 전송 (흐름 제어):")
        print("-" * 40)
        
        for i, segment in enumerate(data_segments):
            if i < self.window_size:
                print(f"전송: Segment {i+1} (SEQ={self.seq_num + i})")
                time.sleep(0.1)
            else:
                print(f"대기: Window full (size={self.window_size})")
                print("ACK 수신 후 계속...")
                self.window_size += 1  # 간단한 윈도우 증가
        
        print("모든 세그먼트 전송 완료\n")
    
    def congestion_control(self):
        """혼잡 제어 (Slow Start)"""
        print("TCP 혼잡 제어 (Slow Start):")
        print("-" * 40)
        
        threshold = 8
        max_window = 16
        
        while self.congestion_window < max_window:
            print(f"CWND: {self.congestion_window} segments")
            
            if self.congestion_window < threshold:
                # Slow Start: 지수적 증가
                self.congestion_window *= 2
                print("  → Slow Start: 윈도우 2배 증가")
            else:
                # Congestion Avoidance: 선형 증가
                self.congestion_window += 1
                print("  → Congestion Avoidance: 윈도우 +1")
            
            # 패킷 손실 시뮬레이션
            if random.random() < 0.1:  # 10% 확률로 손실
                print("  ⚠️ 패킷 손실 감지!")
                threshold = self.congestion_window // 2
                self.congestion_window = 1
                print(f"  → Threshold={threshold}, CWND=1로 리셋")
            
            time.sleep(0.2)
            
            if self.congestion_window >= max_window:
                break

class UDPSimulator:
    """UDP 통신 시뮬레이션"""
    
    def send_datagram(self, data):
        """UDP 데이터그램 전송"""
        print("UDP 데이터그램 전송:")
        print("-" * 40)
        print(f"전송: {data}")
        print("(연결 설정 없음, ACK 없음)")
        print("전송 완료 (신뢰성 보장 X)\n")
        
        # 패킷 손실 시뮬레이션
        if random.random() < 0.2:  # 20% 손실률
            return None
        return data

# TCP 시뮬레이션
tcp = TCPSimulator()
tcp.three_way_handshake()
tcp.send_with_flow_control(['Data1', 'Data2', 'Data3', 'Data4', 'Data5', 'Data6'])
tcp.congestion_control()

# UDP 시뮬레이션
print("\n" + "=" * 60)
udp = UDPSimulator()
for i in range(3):
    result = udp.send_datagram(f"UDP Packet {i+1}")
    if result:
        print(f"수신 확인: {result}")
    else:
        print("⚠️ 패킷 손실!")

TCP/IP 계층별 헤더 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class PacketAnalyzer:
    """패킷 분석기"""
    
    def ethernet_header(self, src_mac, dst_mac):
        """이더넷 헤더 (14 bytes)"""
        return {
            'dst_mac': dst_mac,      # 6 bytes
            'src_mac': src_mac,      # 6 bytes
            'type': '0x0800 (IPv4)'  # 2 bytes
        }
    
    def ip_header(self, src_ip, dst_ip):
        """IP 헤더 (20 bytes minimum)"""
        return {
            'version': 4,             # 4 bits
            'header_length': 20,      # 4 bits
            'tos': 0,                 # 1 byte
            'total_length': 40,       # 2 bytes
            'identification': 12345,  # 2 bytes
            'flags': '010',           # 3 bits
            'fragment_offset': 0,     # 13 bits
            'ttl': 64,               # 1 byte
            'protocol': 6,           # 1 byte (6=TCP)
            'checksum': '0x1234',    # 2 bytes
            'src_ip': src_ip,        # 4 bytes
            'dst_ip': dst_ip         # 4 bytes
        }
    
    def tcp_header(self, src_port, dst_port, seq_num, ack_num):
        """TCP 헤더 (20 bytes minimum)"""
        return {
            'src_port': src_port,    # 2 bytes
            'dst_port': dst_port,    # 2 bytes
            'seq_num': seq_num,      # 4 bytes
            'ack_num': ack_num,      # 4 bytes
            'data_offset': 5,        # 4 bits (5 * 4 = 20 bytes)
            'flags': {               # 9 bits total
                'NS': 0, 'CWR': 0, 'ECE': 0,
                'URG': 0, 'ACK': 1, 'PSH': 0,
                'RST': 0, 'SYN': 0, 'FIN': 0
            },
            'window': 65535,         # 2 bytes
            'checksum': '0x5678',    # 2 bytes
            'urgent_pointer': 0      # 2 bytes
        }
    
    def analyze_packet(self):
        """패킷 분석"""
        print("패킷 구조 분석:")
        print("=" * 60)
        
        # 헤더 생성
        eth = self.ethernet_header("AA:BB:CC:DD:EE:FF", "11:22:33:44:55:66")
        ip = self.ip_header("192.168.1.100", "93.184.216.34")
        tcp = self.tcp_header(54321, 80, 1000, 2000)
        
        # 이더넷 헤더
        print("이더넷 헤더 (Layer 2):")
        for key, value in eth.items():
            print(f"  {key}: {value}")
        
        # IP 헤더
        print("\nIP 헤더 (Layer 3):")
        for key, value in ip.items():
            if key != 'flags':
                print(f"  {key}: {value}")
        
        # TCP 헤더
        print("\nTCP 헤더 (Layer 4):")
        for key, value in tcp.items():
            if key == 'flags':
                flags_str = ', '.join([f for f, v in value.items() if v == 1])
                print(f"  flags: {flags_str if flags_str else 'None'}")
            else:
                print(f"  {key}: {value}")
        
        # 총 헤더 크기
        total_header_size = 14 + 20 + 20  # Ethernet + IP + TCP
        print(f"\n총 헤더 크기: {total_header_size} bytes")

# 패킷 분석
analyzer = PacketAnalyzer()
analyzer.analyze_packet()

🌍 응용 계층 프로토콜

HTTP/HTTPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class HTTPSimulator:
    """HTTP 프로토콜 시뮬레이션"""
    
    def http_request(self, method, url, headers=None):
        """HTTP 요청 생성"""
        request = f"{method} {url} HTTP/1.1\r\n"
        
        default_headers = {
            'Host': 'www.example.com',
            'User-Agent': 'Mozilla/5.0',
            'Accept': 'text/html,application/json',
            'Accept-Language': 'ko-KR,ko;q=0.9,en;q=0.8',
            'Connection': 'keep-alive'
        }
        
        if headers:
            default_headers.update(headers)
        
        for key, value in default_headers.items():
            request += f"{key}: {value}\r\n"
        
        request += "\r\n"  # 헤더 끝
        return request
    
    def http_response(self, status_code, status_text, body):
        """HTTP 응답 생성"""
        response = f"HTTP/1.1 {status_code} {status_text}\r\n"
        
        headers = {
            'Date': 'Sat, 24 Aug 2024 10:00:00 GMT',
            'Server': 'Apache/2.4.41',
            'Content-Type': 'text/html; charset=UTF-8',
            'Content-Length': len(body),
            'Connection': 'keep-alive'
        }
        
        for key, value in headers.items():
            response += f"{key}: {value}\r\n"
        
        response += "\r\n"  # 헤더 끝
        response += body
        
        return response
    
    def status_codes(self):
        """HTTP 상태 코드"""
        return {
            '1xx': 'Informational',
            '100': 'Continue',
            '2xx': 'Success',
            '200': 'OK',
            '201': 'Created',
            '204': 'No Content',
            '3xx': 'Redirection',
            '301': 'Moved Permanently',
            '302': 'Found',
            '304': 'Not Modified',
            '4xx': 'Client Error',
            '400': 'Bad Request',
            '401': 'Unauthorized',
            '403': 'Forbidden',
            '404': 'Not Found',
            '5xx': 'Server Error',
            '500': 'Internal Server Error',
            '502': 'Bad Gateway',
            '503': 'Service Unavailable'
        }

# HTTP 시뮬레이션
http = HTTPSimulator()

# HTTP 요청
print("HTTP 요청:")
print("-" * 60)
request = http.http_request('GET', '/api/users/123')
print(request)

# HTTP 응답
print("HTTP 응답:")
print("-" * 60)
response = http.http_response(200, 'OK', '{"id": 123, "name": "John Doe"}')
print(response)

# 상태 코드
print("\nHTTP 상태 코드:")
print("-" * 60)
codes = http.status_codes()
for code, meaning in codes.items():
    if 'xx' not in code:
        print(f"  {code}: {meaning}")

DNS (Domain Name System)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import socket

class DNSSimulator:
    """DNS 시뮬레이션"""
    
    def __init__(self):
        self.dns_cache = {}
        self.root_servers = ['a.root-servers.net', 'b.root-servers.net']
        self.dns_records = {
            'www.example.com': {
                'A': '93.184.216.34',
                'AAAA': '2606:2800:220:1:248:1893:25c8:1946',
                'MX': 'mail.example.com',
                'TXT': 'v=spf1 include:_spf.example.com ~all'
            }
        }
    
    def dns_lookup(self, domain):
        """DNS 조회 과정"""
        print(f"DNS 조회: {domain}")
        print("-" * 40)
        
        # 1. 로컬 캐시 확인
        if domain in self.dns_cache:
            print(f"1. 캐시 히트: {self.dns_cache[domain]}")
            return self.dns_cache[domain]
        
        print("1. 캐시 미스")
        
        # 2. 재귀적 조회 시뮬레이션
        print("2. DNS 서버에 재귀적 조회 요청")
        print(f"   → Root 서버: {self.root_servers[0]}")
        print("   → TLD 서버: .com")
        print(f"   → 권한 서버: ns1.example.com")
        
        # 3. 응답
        if domain in self.dns_records:
            ip = self.dns_records[domain]['A']
            print(f"3. 응답 수신: {ip}")
            
            # 캐시 저장
            self.dns_cache[domain] = ip
            print(f"4. 캐시 저장 (TTL: 3600)")
            
            return ip
        else:
            print("3. NXDOMAIN (도메인 없음)")
            return None
    
    def reverse_dns(self, ip_address):
        """역방향 DNS 조회"""
        print(f"역방향 DNS 조회: {ip_address}")
        
        # 실제 역방향 조회 시뮬레이션
        for domain, records in self.dns_records.items():
            if records['A'] == ip_address:
                print(f"{ip_address} = {domain}")
                return domain
        
        print(f"  → PTR 레코드 없음")
        return None

# DNS 시뮬레이션
dns = DNSSimulator()

# 정방향 조회
ip = dns.dns_lookup('www.example.com')
print()

# 캐시된 조회
ip = dns.dns_lookup('www.example.com')
print()

# 역방향 조회
domain = dns.reverse_dns('93.184.216.34')

🔒 네트워크 보안

방화벽과 NAT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class NetworkSecurity:
    """네트워크 보안 시뮬레이션"""
    
    def __init__(self):
        self.firewall_rules = []
        self.nat_table = {}
        
    def add_firewall_rule(self, action, protocol, src_ip, dst_ip, dst_port):
        """방화벽 규칙 추가"""
        rule = {
            'action': action,  # ALLOW or DENY
            'protocol': protocol,
            'src_ip': src_ip,
            'dst_ip': dst_ip,
            'dst_port': dst_port
        }
        self.firewall_rules.append(rule)
    
    def check_packet(self, protocol, src_ip, dst_ip, dst_port):
        """패킷 필터링"""
        for rule in self.firewall_rules:
            if (rule['protocol'] == protocol or rule['protocol'] == 'ANY') and \
               (rule['src_ip'] == src_ip or rule['src_ip'] == 'ANY') and \
               (rule['dst_ip'] == dst_ip or rule['dst_ip'] == 'ANY') and \
               (rule['dst_port'] == dst_port or rule['dst_port'] == 'ANY'):
                return rule['action']
        
        return 'DENY'  # 기본 정책
    
    def nat_translation(self, private_ip, private_port):
        """NAT 변환"""
        # PAT (Port Address Translation)
        public_ip = '203.0.113.1'
        public_port = 50000 + len(self.nat_table)
        
        # NAT 테이블에 매핑 저장
        key = f"{private_ip}:{private_port}"
        self.nat_table[key] = f"{public_ip}:{public_port}"
        
        return public_ip, public_port
    
    def setup_dmz(self):
        """DMZ 설정"""
        print("DMZ (Demilitarized Zone) 구성:")
        print("-" * 40)
        
        zones = {
            'External': '0.0.0.0/0',
            'DMZ': '192.168.100.0/24',
            'Internal': '192.168.1.0/24'
        }
        
        rules = [
            "External → DMZ: HTTP(80), HTTPS(443) 허용",
            "DMZ → External: 모든 트래픽 허용",
            "Internal → DMZ: 모든 트래픽 허용",
            "DMZ → Internal: 데이터베이스(3306) 제한적 허용",
            "External → Internal: 모든 트래픽 차단"
        ]
        
        for zone, subnet in zones.items():
            print(f"{zone}: {subnet}")
        
        print("\n방화벽 규칙:")
        for rule in rules:
            print(f"{rule}")

# 네트워크 보안 시뮬레이션
security = NetworkSecurity()

# 방화벽 규칙 설정
security.add_firewall_rule('ALLOW', 'TCP', 'ANY', 'ANY', 80)
security.add_firewall_rule('ALLOW', 'TCP', 'ANY', 'ANY', 443)
security.add_firewall_rule('DENY', 'TCP', 'ANY', 'ANY', 23)  # Telnet 차단

# 패킷 검사
print("방화벽 패킷 필터링:")
print("-" * 40)
packets = [
    ('TCP', '192.168.1.100', '93.184.216.34', 80),
    ('TCP', '192.168.1.100', '93.184.216.34', 23),
    ('TCP', '192.168.1.100', '93.184.216.34', 443)
]

for protocol, src, dst, port in packets:
    result = security.check_packet(protocol, src, dst, port)
    print(f"{src}{dst}:{port} ({protocol}): {result}")

print()

# NAT 변환
print("NAT 변환:")
print("-" * 40)
private_ip = '192.168.1.100'
private_port = 12345
public_ip, public_port = security.nat_translation(private_ip, private_port)
print(f"내부: {private_ip}:{private_port} → 외부: {public_ip}:{public_port}")

print()
security.setup_dmz()

🚀 웹 요청의 전체 과정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def web_request_journey():
    """웹 요청의 전체 여정"""
    
    steps = [
        {
            'step': 1,
            'action': 'URL 입력',
            'detail': '사용자가 브라우저에 www.example.com 입력'
        },
        {
            'step': 2,
            'action': 'DNS 조회',
            'detail': 'DNS 서버에서 도메인의 IP 주소 조회 (93.184.216.34)'
        },
        {
            'step': 3,
            'action': 'TCP 연결',
            'detail': '3-way handshake로 서버와 TCP 연결 설정'
        },
        {
            'step': 4,
            'action': 'TLS 핸드셰이크',
            'detail': 'HTTPS의 경우 TLS 암호화 연결 설정'
        },
        {
            'step': 5,
            'action': 'HTTP 요청',
            'detail': 'GET / HTTP/1.1 요청 전송'
        },
        {
            'step': 6,
            'action': '서버 처리',
            'detail': '서버가 요청을 처리하고 HTML 생성'
        },
        {
            'step': 7,
            'action': 'HTTP 응답',
            'detail': '200 OK와 함께 HTML 콘텐츠 반환'
        },
        {
            'step': 8,
            'action': '브라우저 렌더링',
            'detail': 'HTML 파싱, CSS 적용, JavaScript 실행'
        },
        {
            'step': 9,
            'action': '추가 리소스',
            'detail': '이미지, CSS, JS 파일 추가 요청'
        },
        {
            'step': 10,
            'action': '페이지 완성',
            'detail': '모든 리소스 로드 후 페이지 표시 완료'
        }
    ]
    
    print("웹 페이지 요청의 전체 과정:")
    print("=" * 60)
    
    for item in steps:
        print(f"\nStep {item['step']}: {item['action']}")
        print(f"{item['detail']}")
        
        # 각 단계별 프로토콜
        if item['step'] == 2:
            print("  프로토콜: DNS (UDP port 53)")
        elif item['step'] == 3:
            print("  프로토콜: TCP")
        elif item['step'] == 4:
            print("  프로토콜: TLS 1.3")
        elif item['step'] in [5, 7]:
            print("  프로토콜: HTTP/HTTPS")

web_request_journey()

🎯 핵심 정리

꼭 기억해야 할 5가지

  1. OSI 7계층은 네트워크 통신을 계층별로 추상화
  2. TCP는 신뢰성, UDP는 속도를 우선시
  3. IP 주소는 네트워크 식별, 포트는 프로세스 식별
  4. DNS는 도메인을 IP 주소로 변환
  5. HTTP는 웹의 기반 프로토콜

실무 활용 팁

  • 네트워크 문제 해결 시 계층별로 접근
  • Wireshark 같은 패킷 분석 도구 활용
  • 방화벽 규칙은 최소 권한 원칙 적용
  • HTTPS 사용으로 보안 강화

📚 추가 학습 자료

추천 도서

  • “Computer Networking: A Top-Down Approach” - Kurose & Ross
  • “TCP/IP Illustrated” - Stevens
  • “HTTP: The Definitive Guide”

실습 프로젝트

  1. 간단한 HTTP 서버 구현
  2. 패킷 스니퍼 만들기
  3. 채팅 프로그램 (TCP/UDP)

🚀 다음 시간 예고

다음 포스트부터는 자료구조편이 시작됩니다! 배열과 연결 리스트부터 시작하여 스택, 큐, 트리, 그래프까지 다룰 예정입니다.

✅ 이 글에서 배운 것

스스로 확인해보세요! 각 항목을 설명할 수 있다면 체크하세요.

개념 이해

  • OSI 7계층 모델의 각 계층 역할
  • TCP/IP 4계층 구조
  • IP 주소와 서브넷 마스크의 개념
  • TCP와 UDP의 차이점
  • HTTP와 HTTPS의 차이

실용적 이해

  • DNS가 도메인을 IP로 변환하는 과정
  • 3-way handshake를 통한 TCP 연결 수립
  • 라우팅과 패킷 전송 원리
  • 네트워크 보안의 기초 (암호화, 인증)
  • 포트 번호와 소켓의 역할

실습 완료

  • IP 주소 변환 예제를 실행했다
  • 패킷 구조 시뮬레이션을 이해했다
  • HTTP 요청/응답 예제를 테스트했다
  • DNS 조회 과정을 확인했다

📌 시리즈 네비게이션

순서 제목 링크
1 CS 입문: 컴퓨터 사이언스가 무엇인가? 처음으로
2 컴퓨터 구조: CPU, 메모리, 저장장치의 동작 원리 이전 글
3 이진수와 논리 게이트: 컴퓨터가 생각하는 방법 이전 글
4 운영체제 기초: 프로세스, 스레드, 메모리 관리 ← 이전 글
5 네트워크 기초: OSI 7계층, TCP/IP 이해하기 현재 글
6 배열과 연결 리스트 다음 글 →
📋 전체 시리즈 목차 보기

기초 이론편

  1. CS 입문 ✅
  2. 컴퓨터 구조 ✅
  3. 이진수와 논리 게이트 ✅
  4. 운영체제 기초 ✅
  5. 네트워크 기초 ✅

자료구조편

  1. 배열과 연결 리스트
  2. 스택과 큐
  3. 트리 구조
  4. 그래프
  5. 해시 테이블

알고리즘편

  1. 복잡도 분석
  2. 정렬 알고리즘
  3. 탐색 알고리즘
  4. 동적 계획법
  5. 그리디와 분할정복

실무 응용편

  1. 데이터베이스 이론
  2. 소프트웨어 공학
  3. 보안 기초
  4. 분산 시스템
  5. CS 종합과 면접 준비
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.