기술 학습

Java에서 소켓(socket)은?

hawon6691 2026. 2. 9. 13:12
728x90

Java에서 소켓을 구현할 때 비동기로 작동하는지 여부는 "어떤 API를 사용하느냐"에 따라 달라집니다. Java는 역사적으로 이 문제를 해결하기 위해 세 가지 방식을 발전시켜 왔습니다.


1. Java의 세 가지 방식

① 전통적인 방식 (BIO: Blocking I/O)

처음 Java가 나왔을 때의 방식입니다. java.net.ServerSocket을 사용합니다.

  • 특징: 데이터가 올 때까지 스레드가 멈춰(Blocking) 있습니다.
  • 문제점: 연결이 1,000개면 스레드도 1,000개가 필요합니다. 스레드가 너무 많아지면 메모리가 부족해지고 성능이 급격히 떨어집니다. (비유: 손님 한 명당 점원 한 명이 붙어서 아무것도 못 하고 기다리는 식당)

② 현대적인 방식 (NIO: Non-blocking I/O) — 비동기적 처리

Java 1.4부터 도입된 java.nio 패키지입니다.

  • 특징: 소켓 연결은 계속 유지되지만, 데이터가 왔을 때만 스레드가 반응합니다.
  • 핵심 요소: Selector라는 관리자가 여러 소켓을 관찰하다가, 패킷이 도착한 소켓만 골라 처리합니다.
  • Node.js와의 유사성: Express(Node.js)의 이벤트 기반 방식과 가장 유사하게 동작합니다.

③ 비동기 방식 (AIO: Asynchronous I/O)

Java 7부터 도입되었습니다. AsynchronousServerSocketChannel을 사용합니다.

  • 특징: I/O 작업이 완료되면 운영체제가 프로그램에게 "다 끝났어!"라고 알려줍니다(Callback). 가장 진보된 비동기 방식입니다.

2. Java 코드 예시 (Blocking vs Non-blocking)

[전통적인 Blocking 방식]

보통 한 클라이언트당 스레드 하나를 새로 만들어 비동기처럼 보이게 흉내를 냅니다.

ServerSocket server = new ServerSocket(8080);
while(true) {
    Socket socket = server.accept(); // 여기서 멈춤(Blocking)
    // 새로운 스레드를 생성하여 비동기처럼 처리
    new Thread(() -> {
        // 데이터 읽기/쓰기
    }).start();
}

[현대적인 NIO 방식 (Netty 라이브러리 등)]

실무에서 Java로 고성능 소켓 서버를 만들 때는 Netty라는 라이브러리를 거의 표준처럼 사용합니다. Netty는 내부적으로 NIO를 사용하여 매우 효율적인 비동기 처리를 지원합니다.


3. Node.js(Express) vs Java의 결정적 차이

  • Node.js: 태생부터 싱글 스레드 + 비동기입니다. 개발자가 딱히 설정하지 않아도 소켓 통신이 비동기로 흘러갑니다.
  • Java: 기본은 멀티 스레드 + 동기(Blocking) 중심이었으나, NIO와 AIO를 통해 강력한 비동기 기능을 제공합니다. 대규모 기업용 시스템에서는 Java의 멀티 스레드 비동기 처리가 더 안정적일 때가 많습니다.

요약

"Java에서도 비동기로 작동하나요?"에 대한 답은 "네, 하지만 그렇게 짜야만(NIO/AIO 사용) 합니다."입니다. 전통적인 방식으로 짜면 동기식으로 작동하여 서버 성능에 한계가 올 수 있습니다.

728x90