스레드는 운영 채제애 비용을 먾이 들이는 작업으로 하나의 스레드에서 여러 채널을 관리하며 비용 소모가 적게 들게 되니다. 이런 경우 Selector에 여러개의 스레드를 묶어서 하나의 스레드로 처리하게 됩니다.
작업 순서는 다음과 같습니다.
Selector 생성
선택 가능한 채널 등록
1. selector 생성
Selector selector =Selector.open();
2. 선택 가능한 채널 등록
선택기에는 채널을 사용하기 위해서는 register 메서드로 채널을 등록 해야 하는데 우선 비동기 모드로 설정 되어 있어야 됩니다. 이 말의 의미는 FileChannel을 사용 할 수 없다는 이야기 입니다. 왜냐 하면 FileChannel는 비동기 모드로 동작을 하지 않기 때문입니다.
selector에는 하나 또는 여러개의 채널을 연결할 수 있는데 selector의 select 메소드를 사용하여 선택 합니다. select 메서드는 하나 이상의 채널이 작업을 수행할 준비( (Interest Set : connect, accept, read or write))가 될 때까지 차단됩니다. 반환되는 정수는 채널이 조작을 위해 준비된 키의 수를 나타내는 것으로 다음과 같은 방법으로 얻을 수 있습니다.
int select() : 등록된 이벤트가 하나 이상의 채널이 준비 될 때까지 차단
int select(long timeout) : 최대 허용 시간 까지 차단단
int selectNow() : 차단 하지 않습니다.
5-1. selectedKeys()
준비된 채널의 SelectionKey Set를 통해서 얻을 수 있습니다.
Set<SelectionKey> selectedKeys =selector.selectedKeys();Iterator<SelectionKey> keyIterator =selectedKeys.iterator();while(keyIterator.hasNext()) {SelectionKey key =keyIterator.next();if(key.isAcceptable()) {// a connection was accepted by a ServerSocketChannel. } elseif (key.isConnectable()) {// a connection was established with a remote server. } elseif (key.isReadable()) {// a channel is ready for reading } elseif (key.isWritable()) {// a channel is ready for writing }keyIterator.remove();}
6. 전체 예제
서버
packageorg.example;importjava.io.IOException;importjava.net.InetSocketAddress;importjava.nio.ByteBuffer;importjava.nio.channels.*;importjava.util.Iterator;importjava.util.Set;publicclassJavaNioSocketSever {publicstaticvoidmain(String[] args) {System.out.println("Hello world!");try {JavaNioSocketSever.selectorServerSocketChannel(); } catch (IOException e) {thrownewRuntimeException(e); } }privatestaticvoidselectorServerSocketChannel() throwsIOException {// Select 오픈 ( 생성 )Selector selector =Selector.open();System.out.println("Selector open: "+selector.isOpen());// 서버 소켓 채널 오픈 ( 생성 )ServerSocketChannel serverSocket =ServerSocketChannel.open();InetSocketAddress hostAddress =newInetSocketAddress("localhost",5454);serverSocket.bind(hostAddress);// 비동기 설정serverSocket.configureBlocking(false);// 해당 채널을 연결 수락을 식별하는 작업 SETint ops =serverSocket.validOps();// 서버 소켓 채널에 selector 지정 SelectionKey selectKy =serverSocket.register(selector, ops,null);System.out.println("등록 이후 : "+ selectKy);for (;;) {System.out.println("Waiting for select...");int noOfKeys =selector.select();System.out.println("Number of selected keys: "+ noOfKeys);Set selectedKeys =selector.selectedKeys();Iterator iter =selectedKeys.iterator();while (iter.hasNext()) {SelectionKey ky = (SelectionKey) iter.next();if (ky.isAcceptable()) {// Accept the new client connectionSocketChannel client =serverSocket.accept();client.configureBlocking(false);// Add the new connection to the selectorclient.register(selector,SelectionKey.OP_READ);System.out.println("Accepted new connection from client: "+ client); }elseif (ky.isReadable()) {// Read the data from clientSocketChannel client = (SocketChannel) ky.channel();ByteBuffer buffer =ByteBuffer.allocate(256);client.read(buffer);String output =newString(buffer.array()).trim();System.out.println("Message read from client: "+ output);if (output.equals("Bye.")) {client.close();System.out.println("Client messages are complete; close."); } } // end if (ky...)iter.remove(); } // end while loop } // end for loop }}