Java/Java 구현

Java // 구현 // Server Socket // NIO NonBlocking

문스코딩 2018. 8. 3. 12:58

- NIO NonBlocking 기반 서버

- Selector가 Blocking 되어 있지 않는 "accept() 와 receive()"를 수신시 매칭해주는 중재자 역할을 함

- 클라이언트의 생성과 중지는 "startClient() & stopClient()"의 메소드 오버라이딩이 필요

- 싱글톤으로 전역접근가능

- 제네릭으로 특정 클라이언트 처리


/* ServerOthello - singleton */
public abstract class Server<T> {

private static Server instance;

/* Field */
public ExecutorService executorService;
public ServerSocketChannel serverSocketChannel;
public Selector selector;
public List<T> clients;

/* Constructor */
public Server(short port) {
if(instance != null) return;
instance = this;

this.clients = new Vector<>();
start(port);
}

/* GetInstance */
public static Server getInstance() {
return instance;
}

/* Start */
public void start(short port) {

// == 가용한 프로세서만큼 스레드 생성 ==
executorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ); // 4

try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();

// == 넌블로킹설정 ==
serverSocketChannel.configureBlocking(false);

// == bind(port) ==
serverSocketChannel.bind( new InetSocketAddress(port) );

// == register() ==
serverSocketChannel.register( selector, SelectionKey.OP_ACCEPT );

// == select() ==
select();

} catch (IOException e) {
e.printStackTrace();
}
}

/* Stop */
public void stop() {
try {
if(serverSocketChannel != null && serverSocketChannel.isOpen()) {
serverSocketChannel .close();
}
if(executorService != null && executorService.isShutdown()) {
executorService.shutdown();
}
} catch (IOException e) {}
}

/* Select - 기다려서 분기해주는 메소드 */
protected void select() {
Runnable runnable = new Runnable() {
@Override
public void run() {
while(true) {
try {

// == select() ==
int keyCount = selector.select();
if(keyCount == 0) { continue; }

Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();

while(iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();

// == accept ==
if(selectionKey.isAcceptable()) {
startClient(selectionKey);
}
// == read ==
else if(selectionKey.isReadable()) {
ClientOthello client = (ClientOthello) selectionKey.attachment();
client.receive();
}
// == write ==
else if(selectionKey.isWritable()) { //
ClientOthello client = (ClientOthello) selectionKey.attachment();
client.send();
}

// == (처리완료) Key remove() ==
iterator.remove();
}
} catch (IOException e) {
if(serverSocketChannel.isOpen()) stop();
break;
}
}
}
};
executorService.submit(runnable);
}

/* startClient */
protected abstract void startClient(SelectionKey selectionKey);

/* stopClient */
public abstract void stopClients();

}


반응형