package com.github.nettybook.ch2; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; public class NonBlockingServer { private Map<SocketChannel, List<byte[]>> keepDataTrack = new HashMap<>(); private ByteBuffer buffer = ByteBuffer.allocate(2 * 1024); private void startEchoServer() { try ( Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open() ) { if ((serverSocketChannel.isOpen()) && (selector.isOpen())) { serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(new InetSocketAddress(8888)); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("접속 대기중"); while (true) { selector.select(); Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); while (keys.hasNext()) { SelectionKey key = (SelectionKey) keys.next(); keys.remove(); if (!key.isValid()) { continue; } if (key.isAcceptable()) { this.acceptOP(key, selector); } else if (key.isReadable()) { this.readOP(key); } else if (key.isWritable()) { this.writeOP(key); } } } } else { System.out.println("서버 소캣을 생성하지 못했습니다."); } } catch (IOException ex) { System.err.println(ex); } } private void acceptOP(SelectionKey key, Selector selector) throws IOException { ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); SocketChannel socketChannel = serverChannel.accept(); socketChannel.configureBlocking(false); System.out.println("클라이언트 연결됨 : " + socketChannel.getRemoteAddress()); keepDataTrack.put(socketChannel, new ArrayList<byte[]>()); socketChannel.register(selector, SelectionKey.OP_READ); } private void readOP(SelectionKey key) { try { SocketChannel socketChannel = (SocketChannel) key.channel(); buffer.clear(); int numRead = -1; try { numRead = socketChannel.read(buffer); } catch (IOException e) { System.err.println("데이터 읽기 에러!"); } if (numRead == -1) { this.keepDataTrack.remove(socketChannel); System.out.println("클라이언트 연결 종료 : " + socketChannel.getRemoteAddress()); socketChannel.close(); key.cancel(); return; } byte[] data = new byte[numRead]; System.arraycopy(buffer.array(), 0, data, 0, numRead); System.out.println(new String(data, "UTF-8") + " from " + socketChannel.getRemoteAddress()); doEchoJob(key, data); } catch (IOException ex) { System.err.println(ex); } } private void writeOP(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); List<byte[]> channelData = keepDataTrack.get(socketChannel); Iterator<byte[]> its = channelData.iterator(); while (its.hasNext()) { byte[] it = its.next(); its.remove(); socketChannel.write(ByteBuffer.wrap(it)); } key.interestOps(SelectionKey.OP_READ); } private void doEchoJob(SelectionKey key, byte[] data) { SocketChannel socketChannel = (SocketChannel) key.channel(); List<byte[]> channelData = keepDataTrack.get(socketChannel); channelData.add(data); key.interestOps(SelectionKey.OP_WRITE); } public static void main(String[] args) { NonBlockingServer main = new NonBlockingServer(); main.startEchoServer(); } }