## 자바 NIO (New Input/Output) 관련 클래스 및 주요 메서드 정리 자바 NIO는 기존의 `java.io`보다 **더 빠르고 효율적인 비동기식 입출력 처리**를 제공하는 API다. NIO의 핵심 개념은 **버퍼(Buffer), 채널(Channel), 셀렉터(Selector)**이다. --- ### 1. `Buffer` 클래스 및 주요 메서드 | 메서드 | 설명 | |--------|-----------------------------| | `allocate(int capacity)` | 지정된 크기의 버퍼 생성 (`ByteBuffer.allocate(1024)`) | | `wrap(byte[] array)` | 기존 배열을 감싸는 버퍼 생성 | | `put(T value)` | 버퍼에 데이터 저장 | | `get()` | 버퍼에서 데이터 읽기 | | `flip()` | 읽기 모드로 전환 (쓰기 → 읽기) | | `clear()` | 버퍼를 초기화 (데이터 삭제 X, 포인터 리셋) | | `compact()` | 읽지 않은 데이터를 앞으로 이동하고, 쓰기 모드로 전환 | | `position()` | 현재 읽기/쓰기 위치 반환 | | `limit()` | 읽기/쓰기 가능한 최대 위치 반환 | | `remaining()` | 남은 읽기/쓰기 가능 데이터 개수 반환 | **버퍼의 주요 종류**: - `ByteBuffer` (바이트 저장) - `CharBuffer` (문자 저장) - `IntBuffer`, `FloatBuffer` 등 --- ### 2. `Channel` 인터페이스 및 주요 메서드 | 메서드 | 설명 | |--------|-----------------------------------| | `open(Path path, OpenOption...)` | 파일 채널 열기 (`FileChannel.open(path)`) | | `read(ByteBuffer dst)` | 데이터를 버퍼로 읽음 | | `write(ByteBuffer src)` | 버퍼의 데이터를 채널에 씀 | | `close()` | 채널 닫기 | | `position()` | 현재 위치 반환 | | `size()` | 파일 크기 반환 | | `truncate(long size)` | 파일 크기를 지정한 크기로 자름 | | `force(boolean metaData)` | 버퍼 내용을 강제로 디스크에 저장 | **채널의 주요 종류**: - `FileChannel` (파일 입출력) - `SocketChannel` (TCP 소켓 통신) - `ServerSocketChannel` (TCP 서버 소켓) - `DatagramChannel` (UDP 통신) --- ### 3. `Selector` 클래스 및 주요 메서드 | 메서드 | 설명 | |--------|-----------------------------| | `open()` | 새로운 셀렉터 생성 | | `select()` | I/O 이벤트가 발생할 때까지 대기 | | `selectNow()` | 즉시 이벤트 확인 (블로킹 X) | | `select(timeout)` | 지정된 시간 동안 대기 | | `keys()` | 등록된 모든 채널 반환 | | `selectedKeys()` | 이벤트가 발생한 채널 반환 | | `wakeup()` | 블로킹 상태에서 셀렉터를 깨움 | | `close()` | 셀렉터 닫기 | **관련 클래스**: - `SelectionKey.OP_READ` (읽기 가능) - `SelectionKey.OP_WRITE` (쓰기 가능) - `SelectionKey.OP_CONNECT` (연결 가능) - `SelectionKey.OP_ACCEPT` (새로운 연결 가능) --- ## 자바 NIO 쉽게 설명하기 ### NIO란 무엇인가? NIO는 기존의 `java.io`보다 **더 빠르고 비동기적으로 입출력을 처리**할 수 있는 기술이다. - **기존 방식 (IO)** - 데이터를 **스트림(Stream)** 단위로 처리 - 블로킹 방식 (데이터를 읽거나 쓸 때 작업이 끝날 때까지 대기) - 한 번에 하나의 입출력만 가능 - **NIO 방식** - 데이터를 **버퍼(Buffer)와 채널(Channel)**을 이용해 처리 - 논블로킹 방식 (데이터를 읽거나 쓸 때 대기하지 않고 바로 진행) - 하나의 스레드가 여러 채널을 관리 가능 (셀렉터 사용) --- ### 1. **버퍼(Buffer) 이해하기** 버퍼는 **데이터를 담아두는 공간**이다. IO에서는 데이터를 바로 읽고 쓰지만, **NIO에서는 데이터를 버퍼에 담고 처리**한다. ```java ByteBuffer buffer = ByteBuffer.allocate(1024); // 1KB 크기의 버퍼 생성 buffer.put("Hello NIO".getBytes()); // 데이터 쓰기 buffer.flip(); // 읽기 모드로 변경 byte[] data = new byte[buffer.remaining()]; buffer.get(data); // 데이터 읽기 System.out.println(new String(data)); // "Hello NIO" ``` - `put()` → 데이터를 버퍼에 저장 - `flip()` → 읽기 모드로 변경 - `get()` → 버퍼에서 데이터 읽기 --- ### 2. **채널(Channel) 이해하기** 채널은 **데이터가 오가는 통로**다. 기존의 `InputStream` / `OutputStream` 대신 **파일, 소켓 등과 데이터를 주고받는 역할**을 한다. #### **파일을 읽는 예제 (FileChannel)** ```java Path path = Paths.get("example.txt"); FileChannel channel = FileChannel.open(path, StandardOpenOption.READ); ByteBuffer buffer = ByteBuffer.allocate(1024); channel.read(buffer); // 파일에서 데이터를 읽어 버퍼에 저장 buffer.flip(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); System.out.println(new String(data)); // 파일 내용 출력 channel.close(); ``` - `FileChannel.open()` → 파일을 열고 채널 생성 - `read(ByteBuffer)` → 파일 데이터를 버퍼에 읽기 - `flip()` → 읽기 모드로 변경 - `get()` → 버퍼에서 데이터 가져오기 --- ### 3. **논블로킹 소켓 (SocketChannel) 사용하기** NIO의 강점은 **네트워크 프로그래밍에서 논블로킹 소켓**을 사용할 수 있다는 점이다. 즉, 하나의 스레드가 여러 소켓을 동시에 처리할 수 있다. #### **비동기 TCP 클라이언트 예제** ```java SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); // 논블로킹 모드 설정 socketChannel.connect(new InetSocketAddress("localhost", 8080)); while (!socketChannel.finishConnect()) { System.out.println("연결 시도 중..."); } ByteBuffer buffer = ByteBuffer.wrap("Hello Server".getBytes()); socketChannel.write(buffer); // 서버로 데이터 전송 socketChannel.close(); ``` - `configureBlocking(false)` → 논블로킹 모드 설정 - `connect()` → 서버에 연결 - `write(ByteBuffer)` → 서버로 데이터 전송 --- ### 4. **Selector로 다중 채널 관리하기** 셀렉터(Selector)를 사용하면 **하나의 스레드로 여러 채널을 관리**할 수 있다. 즉, 효율적인 **멀티플렉싱** 처리가 가능하다. #### **비동기 서버 예제** ```java Selector selector = Selector.open(); ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.bind(new InetSocketAddress(8080)); serverChannel.configureBlocking(false); serverChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { selector.select(); // I/O 이벤트 발생할 때까지 대기 for (SelectionKey key : selector.selectedKeys()) { if (key.isAcceptable()) { // 클라이언트 연결 요청 처리 SocketChannel client = serverChannel.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 데이터 읽기 처리 SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); client.read(buffer); buffer.flip(); System.out.println("Received: " + new String(buffer.array()).trim()); } } } ``` - `Selector.open()` → 셀렉터 생성 - `select()` → I/O 이벤트 발생 대기 - `register()` → 채널을 셀렉터에 등록 --- ### 정리 자바 NIO는 **버퍼 + 채널 + 셀렉터**를 이용해 1. **파일 입출력을 빠르게 처리**하고 2. **네트워크 소켓을 논블로킹 방식으로 다룰 수 있게 해준다.** **즉, 적은 스레드로 많은 연결을 처리하는 고성능 서버를 만들 때 강력한 도구가 된다!**