본문 바로가기
Research/Study

[2025.06.29]웹 서버 처리 구조(TCP)

by how-are-you 2025. 6. 29.

1. 애플리케이션 레벨: 소켓 준비 → 요청 처리

  1. 소켓 생성 (socket)
    • 커널 내에 struct socket + struct sock 을 할당
    • 프로세스의 FD 테이블에 struct file 포인터를 연결하고, 정수 인덱스(sockfd)를 반환
      int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  2. 주소 바인딩 (bind)
    • struct inet_sock 에 IP·포트(addr.sin_addr, addr.sin_port) 저장
    • 커널의 포트 테이블(hash)에 등록해, 해당 IP:포트로 들어오는 패킷을 이 소켓으로 라우팅 가능케 함
      bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
  3. 리스닝 시작 (listen)
    • 소켓 상태를 TCP_LISTEN으로 전환
    • SYN 요청을 대기할 백로그 큐(SYN 큐 + 완료 대기 큐) 생성
      listen(sockfd, backlog);
  4. 연결 수락 (accept) → HTTP 파싱 → 라우팅
    • 커널이 백로그 큐에서 완성된 연결을 꺼내 새 FD 반환
    • HTTP 요청 라인·헤더·바디 파싱 → 라우터/미들웨어 → 컨트롤러 → 비즈니스 로직
    • 응답(write()/end()) 후, Keep-Alive 여부에 따라 소켓 재사용 또는 닫기
      const conn = await accept(sockfd); // 또는 epoll/select 로 FD 이벤트 감지
  5. 로그·정리
    • 요청·응답 로그 기록
    • 클라이언트가 연결 종료 시, 커널이 소켓 자료구조를 해제

2. 커널 레벨(“백그라운드”): 패킷 처리 & 핸드셰이크

  1. NIC 인터럽트 발생
    • 물리계층 이더넷 프레임 수신 → NIC → CPU 인터럽트
    • 드라이버가 sk_buff 버퍼에 프레임 저장, 체크섬 검사
  2. SoftIRQ (NET_RX_SOFTIRQ)
    • 인터럽트 컨텍스트 일부 처리 → 나머지 TCP 프로토콜 처리는 소프트IRQ에서 분리 실행
    • tcp_rcv_state_process() 등으로 SYN/SYN-ACK/ACK 3-웨이 핸드셰이크 자동 관리
  3. 백로그 큐 등록
    • 핸드셰이크 완료된 연결은 리스닝 소켓의 완료 대기(backlog) 큐 로 적재
  4. 애플리케이션의 accept/epoll 호출 시
    • accept() → 커널이 백로그에서 연결 꺼내 새 struct socket/새 FD 생성
    • epoll/select → 읽기 가능한 FD 이벤트로 알림
  5. 데이터 송·수신
    • 수신: 커널 rx 버퍼 → read()/recv() 로 애플리케이션 메모리로 복사
    • 송신: write()/send() 로 커널 tx 버퍼에 복사 → TCP 세그먼트로 분할 → NIC 전송

전체 요약

  1. socket → bind → listen: 애플리케이션이 커널에 소켓 열고, IP:포트 등록
  2. 패킷 입출력: 커널 네트워크 스택(NIC 드라이버, SoftIRQ, TCP 프로토콜)이 백그라운드에서 처리
  3. accept/epoll → read/write: 애플리케이션은 커널이 준비한 연결 및 데이터를 시스템 콜로 가져와 HTTP 처리

이렇게 애플리케이션커널이 역할을 분리해, 네트워크 I/O를 효율적으로 처리하게 됩니다.