java.nio.channels.Selector 사용법 정리
한개의 Process에서 여러개의 Socket을 다루는 방법은 크게 두가지가 있다.
1. Thread
2. IO Multiplexing
내가 10년 전에 C/C++로 네트웍 프로그래밍을 땐 간단했었다. select() (참고 : http://man7.org/linux/man-pages/man2/select_tut.2.html ) 함수 하나만 제대로 알면 모든 것을 정복할 수 있었다. 게다가 Blocking Socket 으로 Multiplexing을 구현할 수도 있었다. C/C++에선 간결한 API를 통해 너무 쉽게 적용할 수 있었다.
최근 Java로 네트웍 프로그래밍 할 일이 있었는데, 처음 접한 네트웍 프로그래밍이라 그런지 복잡하게 느껴졌다. C의 select() 를 대신할 Selector부터 쉬운 접근은 아니었다.
다음을 차근 차근 따라해보면 답이 보이겠지만 처음이라면 쉬운 접근은 아닌 듯 하다.
1. selector = Selector.open()
2. server = ServerSocketChannel.open(); // Server Socket 을 여는 경우
server.socket().bind(new InetSocketAddress( PORT ));
server.configureBlocking(false);
server.register(selector, SelectionKey.OP_ACCEPT);
SocketChannel ( ServerSocketChannel )객체에서 register(selector, Options) 해야 함.
4가지 옵션이 있음. SelectionKey.OP_ACCEPT, OP_READ, OP_WRITE, OP_CONNECT
단독으로 쓰거나 중복 가능. 중복은 ( SelectionKey.OP_READ | SelectionKey.OP_WRITE )
register() 전에 configureBlocking(false) 해서 non-blocking 모드로 설정해야 함.
3. selector.select() 를 통해 옵션에 따른 대기 중인 SocketChannel을 알아내기.
4. 각 상황에 맞는 처리.
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while(iter.hasNext())
{
SelectionKey key = iter.next();
if( key.isAcceptable() )
{
ServerSocketChannel serversocket = (ServerSocketChannel) key.channel();
SocketChannel client = serversocket.accept();
}
else if( key.isReadAble() )
{
SocketChannel socket = (SocketChannel) key.channel();
}
else if( key.isWriteAble() )
{
SocketChannel socket = (SocketChannel) key.channel();
}
0. 끊거나 끊겼을 경우
key.cancel();
key.channel.close();
보통 Socket이 끊겼는지 여부는 read()을 호출하였을 때 return value가 -1이면 끊긴 것이다.
내가 평소에 사용하는 방법
Selector selector = null;
ServerSocketChannel server = null;
selector = Selector.open();
server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress( PORT ));
server.configureBlocking(false);
server.register(selector, SelectionKey.OP_ACCEPT);
while(true)
{
int rv = selector.select(300);
if (rv == 0)
continue
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while(iter.hasNext())
{
SelectionKey key = iter.next();
if ( key.isAcceptable() )
{
SocketChannel client = key.channel().accept();
if (client != null)
{
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ); // 수신만 원하는 경우
}
}
if ( key.isReadable() )
{
SocketChannel socket = (SocketChannel) key.channel();
}
else if( key.isWriteable() )
{
SocketChannel socket = (SocketChannel) key.channel();
}
}
}
'IT' 카테고리의 다른 글
라즈베리파이로 에어컨 제어하기 #1 (0) | 2015.06.13 |
---|---|
스마트폰의 위치 측정( 모바일 네트워크, WiFi, GPS, GLONASS ) (0) | 2015.02.23 |
UTF-8, UTF-16 차이 (1) | 2014.12.12 |
Python Standard Output의 Encoding 문제 해결 (0) | 2014.12.11 |
Java ArrayList, Vector, LinkedList 자료형 비교 (시간 복잡도 중심으로...) (0) | 2014.11.18 |