1. 톰캣과 HTTP의 관계
HTTP 는 서버가 대화하는 텍스트 규칙에 대한 프로토콜이다.
톰캣은 내부적으로 JAVA의 Socket 라이브러리를 사용해서 만들어진 프로그램이다.
HTTP 메시지는 생각보다 커서 패킷으로 쪼개져서 전송된다.
-> 하나의 HTTP 요청, 응답은 네트워크를 건널때, 수십, 수백개의 패킷으로 쪼개져서 이동한다.
서버가 실행되면(run)
1. 톰캣이 켜지면서 리스닝 소켓이 생성된다.
2. 브라우저 요청이 도착하면 리스닝 소켓이 연결소켓을 생성한다. (리스닝 소켓이 OS 커널에게 브라우저 요청을 토스, OS 커널이 연결 소켓을 생성 후 리스닝 소켓에게 반환, 리스닝 소켓이 연결 소켓을 톰캣에게 반환)
3. 톰캣은 미리 만들어둔 스레드 풀(Thread Pool)에서 스레드 하나를 골라, 생성된 연결 소켓을 할당한다.
4. 스레드는 연결소켓을 통해 들어오는 0과1의 데이터를 읽고 HttpSevletRequest 객체로 변환한다.
2. 소켓과 포트의 관계
TCP 구조
소켓에는 리스닝 소켓 (Listening Socket) 과 연결 소켓 (Connected Socket) 이 존재한다.
리스닝 소켓은 8080번과 같은 포트를 바인딩하고 연결 요청을 처리한다.
연결이 성사되면 실제 통신을 담당할 새로운 소켓, 연결소켓을 생성한다.
( 3-way Handshake가 진행되는 동안은 SYN Queue에 있다가, 완전히 성공(ACK 수신)해야 Accept Queue로 이동하며, 이때 비로소 애플리케이션이 사용할 수 있는 연결 소켓이 생성됨. )
여러개의 연결 요청이 동시에 들어온 경우, 운영체제 커널 내부의 Queue를 통해 순차적으로 처리한다.
만약 리스닝 소켓이 닫힌다면 새로운 연결요청을 받을 수 없지만 기존에 연결되어있는 연결소켓들은 계속 통신한다.
연결소켓은 실제 데이터가 지나다니는 통로역할을 수행한다.
연결이 종료되기 전까지 계속 연결을 유지한다.
ServerSocket listenSocket = new ServerSocket(8080); // 1. 안내원 생성
while(true) {
// 2. 손님 올 때마다 '새로운 소켓' 탄생! (1:1 매칭)
Socket newSocket = listenSocket.accept();
new Thread(() -> handle(newSocket)).start();
}
커널은 패킷 헤더의 4-Tuple(출발지IP/Port, 도착지IP/Port)을 확인하여 해당 소켓을 찾고, 패킷들을 순서대로 재조립하여 그 소켓의 수신 버퍼(Receive Buffer) 메모리 공간에 복사해 넣는다.
연결소켓은 출발지 IP, 출발지 Port, 도착지 IP, 도착지 Port 로 구별된다.
이러한 식별 정보들은 패킷에 저장되어 있는데
각각 IP 헤더 / TCP 헤더에 저장되어 있다.
-------------------------------------------------------------------
| [IP Header] | [TCP Header] | [Payload / Data] |
| | | |
| Src IP: | Src Port: | GET /index.html |
| 111.111.1.1 | 54321 | Host: naver.com |
| | | |
| Dst IP: | Dst Port: | (우리가 보낸 편지 내용) |
| 202.131.30.1 | 80 | |
-------------------------------------------------------------------
(1) (2) (3)
UDP 구조
연결(Connection) 개념이 없으므로, 소켓 하나가 모든 클라이언트의 요청을 받는다. 누가 보냈는지에 대한 식별 정보는 패킷 헤더에 있으므로, 이를 통해 데이터그램(Datagram) 단위로 데이터를 뽑아낸다.
// 1. 소켓 하나 생성 (리스닝/연결 구분 없음)
DatagramSocket socket = new DatagramSocket(8080);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while(true) {
// 2. accept()가 없다!
// 그냥 이 소켓 하나로 세상 모든 사람의 패킷을 다 받는다.
socket.receive(packet);
System.out.println("보낸 사람: " + packet.getAddress());
System.out.println("내용: " + new String(packet.getData()));
}
3. 라우터
네트워크 라우터 : 서로 다른 네트워크를 연결해주는 장비
4. 서버한대에 몇명까지 접속할 수 있는가
리눅스는 소켓을 파일로 취급한다. 모든 연결 소켓은 **파일 디스크립터(File Descriptor)**라는 파일 핸들을 하나씩 차지한다. 따라서 1차적으로는 운영체제가 설정해 둔 **'최대 파일 개수 제한(ulimit)'**만큼 접속할 수 있다. (기본 설정은 보통 1,024개로 매우 적으니 튜닝이 필수다.)
소켓 1개를 유지하는 데는 RAM이 소모된다. 소켓이 생성되면 커널 내부에 수신/송신 버퍼와 관리 구조체가 생성되는데, 이것이 메모리를 차지한다.
결론: RAM 용량이 허락하는 한 무한히 생성 가능하다. 운영체제 설정(ulimit)을 충분히 늘려준다면, 그 다음 한계는 물리적인 RAM 용량이다. 즉, "서버의 RAM이 버틸 수 있는 만큼 소켓을 만들 수 있고, 딱 그만큼 동시 접속자를 받을 수 있다"는 말이 정답이다. (최신 기술을 쓰면 서버 한 대로 수십만~수백만 접속도 가능하다.)
단, '접속 유지(Connection)'와 '요청 처리(Processing)'는 다르다. RAM이 많아서 100만 명을 연결해 둘 수는 있지만, 그 100만 명이 동시에 복잡한 계산을 요청하면 그때는 RAM이 아니라 CPU가 터져서 서버가 멈출 수 있다.
'컴퓨터 네트워크' 카테고리의 다른 글
| CDN(콘텐츠 분배 네트워크) (0) | 2025.11.06 |
|---|---|
| NAT (Network Address Translation) (0) | 2025.10.24 |
| DNS (Domain Name System) (0) | 2025.10.13 |
| 2. 애플리케이션 계층 (0) | 2025.04.24 |
| 1. 컴퓨터 네트워크와 인터넷 (0) | 2025.03.11 |