[05.03/week08] TIL

CHO WanGi·2025년 5월 3일

KRAFTON JUNGLE 8th

목록 보기
45/89

오늘 하루 요약

반성합니다...

✏️ 오늘의 한 일

  • CSAPP Echo Server 2회차
  • OSI 7계층. TCP/IP 4계층

🌈오늘의 성장!

Echo Server

=========================================
에코 클라이언트/서버 로컬 통신 흐름도 (텍스트 기반)
=========================================

--- 1. 서버 준비 단계 ---

[서버 프로세스]
  - 실행 시작 (./echoserveri <포트번호>)
  - CALLS: Open_listenfd(포트번호)
      |
      |--> [커널]
      |     - getaddrinfo() 수행 (NULL 호스트, 포트번호, AI_PASSIVE)
      |     - socket() 호출 -> listenfd 생성
      |     - setsockopt() 호출 (SO_REUSEADDR 설정)
      |     - bind() 호출 (listenfd를 와일드카드 주소:포트번호에 바인딩)
      |     - listen() 호출 (listenfd를 리스닝 상태로 만듦)
      |<-- 반환: listenfd (예: 3)
  - WHILE (1) 루프 시작
  - CALLS: Accept(listenfd, ...)
  - 상태: **BLOCKED** (listenfd에서 클라이언트 연결 요청 대기)

--- 2. 클라이언트 연결 요청 단계 ---

[클라이언트 프로세스]
  - 실행 시작 (./echoclient localhost <포트번호>)
  - CALLS: Open_clientfd("localhost", 포트번호)
      |
      |--> [커널]
      |     - getaddrinfo() 수행 ("localhost", 포트번호, SOCK_STREAM)
      |     - socket() 호출 -> clientfd 생성 (예: 3)
      |     - Connect(clientfd, {127.0.0.1:포트번호}, ...) 호출
      |     - (루프백 통해) TCP 3-way handshake 시도
      |     - 클라이언트 측 임시 포트 할당 (예: 37246)
      |<-- 연결 결과 대기
  - 상태: **BLOCKED** (Connect 함수 내에서 연결 결과 대기)

--- 3. 연결 수립  준비 완료 단계 ---

[커널]
  - TCP 3-way handshake 완료
  - 연결 정보 생성: (127.0.0.1:37246 <-> 127.0.0.1:포트번호)
  - 서버 프로세스 깨우기 (listenfd에 연결 준비 완료 이벤트)
  - 클라이언트 프로세스 깨우기 (Connect 성공 이벤트)

[서버 프로세스]
  - 상태: **WAKE UP** (Ready 상태) -> Running 상태
  - Accept() 함수 반환
      - 반환 값: 새로운 연결 소켓 connfd (예: 4)
      - clientaddr 구조체에 클라이언트 주소({127.0.0.1:37246}) 채워짐
  - CALLS: Getnameinfo(...) -> 클라이언트 정보 얻기
  - CALLS: printf("Connected to...") -> 연결 정보 출력
  - CALLS: echo(connfd) -> 에코 함수 시작
      |
      |--> [echo 함수 내부]
      |     - CALLS: Rio_readinitb(&rio, connfd)
      |     - CALLS: Rio_readlineb(&rio, ...) -> 데이터 기다림
      |     - 상태: **BLOCKED** (connfd에서 클라이언트 데이터 대기)

[클라이언트 프로세스]
  - 상태: **WAKE UP** (Ready 상태) -> Running 상태
  - Connect() 함수 성공 반환 (0) -> Open_clientfd() 성공 반환 (clientfd 3)
  - CALLS: Rio_readinitb(&rio, clientfd)
  - CALLS: printf("Connected...")
  - CALLS: printf("Type input: ")
  - CALLS: Fgets(..., stdin) -> 사용자 입력 기다림
  - 상태: **BLOCKED** (stdin에서 사용자 입력 대기)

--- 4. 데이터 교환 단계 (클라이언트가 "Hi\\n" 전송) ---

[클라이언트 프로세스]
  - 사용자가 "Hi" 입력 후 Enter
  - Fgets() 함수 반환 ("Hi\n" 읽음)
  - 상태: **Running**
  - CALLS: Rio_writen(clientfd, "Hi\n", 3)
      |
      |--> [커널]
      |     - "Hi\n" 데이터를 루프백 통해 서버 측 connfd로 전송
      |     - 서버 프로세스 깨우기 (connfd에 데이터 도착 이벤트)
  - CALLS: Rio_readlineb(&rio, ...) -> 서버 응답 기다림
  - 상태: **BLOCKED** (clientfd에서 서버 에코 응답 대기)

[서버 프로세스 (echo 함수 내부)]
  - 상태: **WAKE UP** (Ready 상태) -> Running 상태
  - Rio_readlineb() 함수 반환 (3, buf="Hi\n")
  - CALLS: printf("server received 3 bytes\n")
  - CALLS: Rio_writen(connfd, "Hi\n", 3)
      |
      |--> [커널]
      |     - "Hi\n" 데이터를 루프백 통해 클라이언트 측 clientfd로 전송
      |     - 클라이언트 프로세스 깨우기 (clientfd에 데이터 도착 이벤트)
  - CALLS: Rio_readlineb(&rio, ...) -> 다음 데이터 기다림
  - 상태: **BLOCKED** (connfd에서 클라이언트 데이터 대기)

[클라이언트 프로세스]
  - 상태: **WAKE UP** (Ready 상태) -> Running 상태
  - Rio_readlineb() 함수 반환 (3, buf="Hi\n")
  - CALLS: Fputs("Hi\n", stdout) -> 화면에 "Hi" 출력
  - CALLS: printf("Type input: ")
  - CALLS: Fgets(..., stdin) -> 사용자 입력 기다림
  - 상태: **BLOCKED** (stdin에서 사용자 입력 대기)

--- 5. 연결 종료 단계 (클라이언트가 Ctrl+D 입력) ---

[클라이언트 프로세스]
  - 사용자가 Ctrl+D 입력 (EOF)
  - Fgets() 함수 NULL 반환
  - 상태: **Running**
  - while 루프 종료
  - CALLS: Close(clientfd)
      |
      |--> [커널]
      |     - 클라이언트 측 소켓 닫음
      |     - TCP FIN 패킷을 루프백 통해 서버 측 connfd로 전송
      |     - 서버 프로세스 깨우기 (connfd에 EOF 이벤트)
  - CALLS: printf("Connection closed.")
  - CALLS: exit(0) -> 프로세스 종료

[서버 프로세스 (echo 함수 내부)]
  - 상태: **WAKE UP** (Ready 상태) -> Running 상태
  - Rio_readlineb() 함수 반환 (0, EOF 감지)
  - while 루프 종료
  - echo() 함수 종료 및 반환

[서버 프로세스 (main 함수)]
  - echo() 함수로부터 복귀
  - CALLS: Close(connfd) -> 해당 클라이언트 연결 소켓 닫음
  - CALLS: printf("Closed connection...")
  - while(1) 루프의 처음으로 돌아감
  - CALLS: Accept(listenfd, ...) -> 다음 연결 기다림
  - 상태: **BLOCKED** (listenfd에서 클라이언트 연결 요청 대기)

그림으로 그리면 이렇다.

OSI 7 계층, TCP/IP 4계층

소켓 프로그래밍 전에 알아야 할 TCP/IP 기초

소켓 프로그래밍은 네트워크 통신의 기반 위에서 동작합니다. 따라서 기본적인 TCP/IP 프로토콜 스택에 대한 이해는 필수입니다. 이 글에서는 IP, TCP, UDP 프로토콜의 특징과 TCP/IP 4계층 모델에 대해 알아보겠습니다.

핵심 프로토콜: IP, TCP, UDP

IP (Internet Protocol)

  • 역할: 지정된 IP 주소(목적지)로 데이터 조각, 즉 패킷(Packet)을 가능한 빠르게 보내는 데 집중합니다.
  • 특징:
    • 비연결형(Connectionless): 데이터를 보내기 전에 상대방과 연결을 설정하지 않습니다.
    • 비신뢰성(Unreliable): 패킷이 목적지까지 전달되는 것을 보장하지 않습니다. 패킷이 중간에 사라지거나, 순서가 뒤바뀌어 도착할 수 있습니다. IP는 일단 최선을 다해 보내는 역할만 합니다.
  • 요약: "최대한 노력해서, 순서나 도착 보장 없이, 빠르게 패킷 전달"

TCP (Transmission Control Protocol)

  • 역할: IP 위에서 동작하며, 데이터 전달을 보증하고, 보낸 순서대로 데이터를 받을 수 있도록 합니다.
  • 특징:
    • 연결 지향형(Connection-oriented): 데이터를 보내기 전에 3-Way Handshake라는 과정을 통해 클라이언트와 서버 간의 논리적인 연결을 설정합니다.
    • 신뢰성(Reliable): 데이터 분실 시 재전송을 요청하고, 도착한 패킷의 순서를 재조립하여 애플리케이션에게 순서대로 전달합니다. (패킷 검사, 순서 재조합, 누락 시 재요청 등)
  • 3-Way Handshake: TCP 연결 설정 과정
    1. SYN (Synchronization): 클라이언트가 서버에게 연결 요청과 함께 임의의 시퀀스 번호(ISN)를 보냅니다. "연결 시작해도 될까요? 제 시작 번호는 X입니다."
    2. SYN-ACK (Synchronization-Acknowledgement): 서버는 클라이언트의 요청을 수락하며, 클라이언트의 시퀀스 번호에 대한 확인(ACK)과 서버 자신의 시퀀스 번호(ISN)를 함께 보냅니다. "네, 요청 잘 받았어요(ACK X+1). 제 시작 번호는 Y입니다."
    3. ACK (Acknowledgement): 클라이언트는 서버의 시퀀스 번호를 확인했다는 응답(ACK)을 보냅니다. "네, 알겠습니다(ACK Y+1)." 이 과정이 끝나면 연결이 수립됩니다.
  • 요약: "연결 설정 후, 순서와 도착을 보장하며, 안정적으로 데이터 전달"

UDP (User Datagram Protocol)

  • 역할: IP와 거의 유사하게 동작하지만, 프로세스(애플리케이션)를 식별하기 위한 포트(Port) 정보와 데이터 오류 검사를 위한 체크섬(Checksum) 기능을 추가로 제공합니다.
  • 특징:
    • 비연결 지향형: TCP와 달리 사전에 연결을 설정하지 않습니다.
    • 비신뢰성: 데이터 전송이나 순서를 보장하지 않습니다. (IP의 특징을 거의 그대로 가짐)
    • 속도: TCP보다 과정이 단순하여 전송 속도가 빠릅니다.
  • 요약: "포트 번호 추가된 IP. 빠르지만, 순서나 도착 보장 없음"

OSI 7계층과 TCP/IP 4계층 모델

네트워크 통신 과정을 역할별로 나누어 설명하는 모델입니다. OSI 7계층이 더 이론적이고 상세하며, TCP/IP 4계층(혹은 5계층) 모델이 실제 인터넷에서 주로 사용되는 모델입니다.

  • TCP/IP 4계층 기준 매핑:
    • 응용 계층 (Application Layer): OSI 7, 6, 5 계층 (Application, Presentation, Session)
    • 전송 계층 (Transport Layer): OSI 4 계층 (Transport)
    • 인터넷 계층 (Internet Layer): OSI 3 계층 (Network)
    • 네트워크 접근 계층 (Network Access Layer / Link Layer): OSI 2, 1 계층 (Data Link, Physical)

TCP/IP 4계층 상세

  • 역할: 같은 네트워크 대역(LAN)에 있는 장치(노드) 간의 신뢰성 있는 데이터 전송을 담당합니다. 물리적인 연결과 데이터 프레임 생성을 다룹니다.
  • 주요 기능:
    • 데이터 패킷을 전기 신호로 변환하여 케이블 등을 통해 물리적으로 전송.
    • MAC 주소를 사용하여 로컬 네트워크 내에서 하드웨어를 식별하고 데이터를 정확한 장치로 전달.

인터넷 계층 (Internet Layer)

  • 역할: 서로 다른 네트워크 간의 데이터 전송, 즉 라우팅(Routing)을 담당합니다. 데이터의 최종 목적지까지 최적의 경로를 찾아 패킷을 전송합니다.
  • 주요 프로토콜:
    • IP: 핵심 프로토콜. 데이터에 출발지/목적지 IP 주소를 추가하고 경로를 설정하여 패킷 전송.
    • ICMP: IP 통신 중 발생하는 오류 보고나 진단 기능을 제공 (e.g., ping).
    • ARP: 논리 주소인 IP 주소를 이용해 같은 네트워크 대역 내 상대방의 물리 주소(MAC 주소)를 알아내는 프로토콜.
    • (RARP): MAC 주소를 통해 IP 주소를 알아오는 프로토콜 (현재는 DHCP가 주로 사용).
  • IP 주소 vs MAC 주소:
    • IP 주소: 인터넷 상에서 컴퓨터(네트워크)의 논리적인 위치 (e.g., 서울시 중랑구 봉화산로 130 - 건물 주소).
    • MAC 주소: 네트워크 카드(하드웨어)에 부여된 고유한 물리 주소 (e.g., 1203호 - 특정 세대 호수).
    • 데이터가 최종 목적지 컴퓨터에 도달하려면 인터넷 전체에서는 IP 주소를 보고 경로를 찾아가고, 해당 컴퓨터가 속한 로컬 네트워크 안에서는 MAC 주소를 보고 정확한 장치로 전달됩니다.

전송 계층 (Transport Layer)

  • 역할: 최종 목적지 컴퓨터 내에서 실행 중인 특정 프로세스(애플리케이션) 간의 데이터 전송을 담당합니다. 포트 번호를 사용하여 데이터를 올바른 애플리케이션으로 전달합니다.
  • 주요 프로토콜:
    • TCP: 신뢰성 있는 연결 기반 통신 제공.
    • UDP: 비신뢰성 데이터그램 통신 제공.

응용 계층 (Application Layer)

  • 역할: 사용자가 직접 사용하는 네트워크 응용 서비스와 관련된 프로토콜들을 정의합니다. 사용자와 가장 가까운 계층입니다.
  • 주요 프로토콜:
    • HTTP: 웹 페이지 전송.
    • FTP: 파일 전송.
    • SMTP: 이메일 전송.
    • DNS: 도메인 이름을 IP 주소로 변환.
  • 웹 브라우저, 이메일 클라이언트 등의 프로그램이 이 계층에서 동작합니다.

TCP/IP 4계층 동작 예시: 네이버 접속

  1. [사용자] 웹 브라우저 주소창에 www.naver.com 입력.
  2. [응용 계층]
    • DNS 프로토콜을 사용하여 www.naver.com에 해당하는 IP 주소를 찾습니다.
    • 웹 페이지를 요청하기 위한 HTTP 메시지(요청 데이터)를 생성합니다.
  3. [전송 계층]
    • HTTP 메시지에 TCP 헤더를 추가합니다. 여기에는 출발지 포트 번호(브라우저가 임의로 할당), 목적지 포트 번호(HTTP는 보통 80번), 순서 번호, 확인 번호 등이 포함됩니다. (TCP 세그먼트 생성)
  4. [인터넷 계층]
    • TCP 세그먼트에 IP 헤더를 추가합니다. 여기에는 출발지 IP 주소(내 컴퓨터), 목적지 IP 주소(DNS로 찾은 네이버 서버 IP) 등이 포함됩니다. (IP 패킷 생성)
  5. [네트워크 접근 계층]
    • IP 패킷에 이더넷 헤더(프레임 헤더)를 추가합니다. 여기에는 출발지 MAC 주소(내 컴퓨터 랜카드), 목적지 MAC 주소(다음 장비, 보통 로컬 네트워크의 게이트웨이 라우터) 등이 포함됩니다. (이더넷 프레임 생성)
  6. [물리 전송] 생성된 프레임이 전기 신호로 변환되어 네트워크 케이블(혹은 무선)을 통해 전송됩니다.
  7. [라우팅] 데이터는 여러 라우터(인터넷 계층에서 동작)를 거치며 목적지 IP 주소를 보고 네이버 서버가 있는 네트워크까지 전달됩니다. 각 구간을 지날 때마다 이더넷 헤더의 MAC 주소는 변경됩니다.
  8. [네이버 서버 도착]
    • 서버의 네트워크 접근 계층이 프레임을 받아 이더넷 헤더 제거.
    • 인터넷 계층이 IP 패킷을 받아 IP 헤더 제거.
    • 전송 계층이 TCP 세그먼트를 받아 TCP 헤더 제거하고, 포트 번호(80번)를 확인하여 해당 포트에서 대기 중인 웹 서버 프로세스로 데이터(HTTP 요청 메시지) 전달.
    • 응용 계층(웹 서버)이 HTTP 요청을 처리하고, 응답 데이터를 생성하여 역순으로 클라이언트에게 다시 보냅니다.

⛏ 오늘의 삽질

Encapsulation, Decapsulation 과정 헷갈려서 잘못 설명함...

profile
제 Velog에 오신 모든 분들이 작더라도 인사이트를 얻어가셨으면 좋겠습니다 :)

0개의 댓글