안녕하세요 알통몬입니다. 공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!! 포스팅 내용이 찾아주신 분들께 도움이 되길 바라며 더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^
|
이전 포스팅과 이어집니다.
2017/04/21 - [자바] - 자바 NIO TCP 넌블로킹 채널 - 넌블로킹 방식의 특징, 셀렉터의 생성과 등록
Selector 를 구현하려면 select()를 호출해야 합니다. select()는 관심 키셋에 저장된 SelectionKey 로부터
작업 처리 준비가 됐다는 통보가 올 때까지 대기합니다(블로킹).
최소한 하나의 SelectionKey 로부터 작업 처리 준비가 됐다는 통보가 오면 리턴을 하고
리턴 값은 통보해온 SelectionKey 의 수입니다.
위 세 종류의 select() 중에 첫 번째 select()가 자주 사용됩니다.
이 메소드는 블로킹되므로 UI 처리 및 이벤트를 처리하는 스레드에서는 호출이 안되고,
별도의 작업 스레드를 생생해서 실행해야 합니다.
select()가 리턴되는 경우 3가지
- 채널이 작업 처리 준비가 됐다는 통보를 할 경우
- Selector 의 wakeup() 을 호출할 경우
- select() 를 호출한 스레드가 인터럽트 될 경우
ServerSocketChannel은 작업 유형이 OP_ACCEPT 밖에 없지만
SocketChannel 은 상황에 따라 읽기 작업과 쓰기 작업을 번갈아 가면서 작업 유형을 변경할 수 있습니다.
채널의 작업 유형이 변경되면 SelectionKey 의 작업 유형을 interestOps() 로 변경해야
스레드가 채널 작업을 할 수 있습니다.
예)
SelectionKey의 작업 유형을 OP_WRITE로 변경하는 코드 selectionKey.interestOps(SelectionKey.OP_WRITE); selectionKey.wakeup(); |
SelectionKey 의 작업 유형이 바뀌면 Selector 의 wakeup() 을 호출해 블로킹되어 있는 select()를
즉시 리턴하고 변경된 작업 유형을 감지하도록 select()를 다시 실행해야 합니다.
select() 가 1이상의 값을 리턴하는 경우 selectedKeys() 로 작업 처리 준비된 SelectionKey들을
Set 컬렉션으로 얻을 수 있습니다.
=> 선택된 키셋
예)
int keyCount = selector.select(); if(keyCount>0){ Set<SelctionKey> selectedKeys = selector.selectedKeys(); |
채널 작업 처리 :
작업 스레드가 해야 할 일은 선택된 키셋에서 SelectionKey 를 하나 씩 꺼내 작업 유형 별로 채널 작업을
처리하는 것입니다.
어떤 작업 유형인지 알아내려면 SelectionKey 의 메소드 중에서 어떤 것이 true를 리턴하는지 조사하는 것입니다.
예제 코드)
작업 스레드가 작업 유형 별로 채널 작업을 처리하는 코드. Thread thread = new Thread() { @Override public void run() { while(true) { try { int keyCount = selector.select(); // 작업 처리 준비된 키 감지함 if(keyCount == 0) { continue; } Set<SelectionKey> selectedKeys = selector.selectedKeys(); //선택된 키셋 얻음 Iterator<SelectionKey> iterator = selectedKeys.iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); if (selectionKey.isAcceptable()) { //연결 수락 작업 처리코드 } else if (selectionKey.isReadable()) { //읽기 작업 처리코드 } else if (selectionKey.isWritable()) { //쓰기 작업 처리코드 } iterator.remove();//선택된 키셋에서 처리 완료된 SelectionKey제거 } } catch (Exception e) { if(serverSocketChannel.isOpen()) { stopServer(); } break; } } } }; thread.start(); |
작업 스레드가 채널 작업을 처리하기위해서는 채널 객체가 필요합니다.
SelectionKey 의 channel()을 호출하여 얻을 수 있습니다.
예)
작업 유형이 OP_ACCEPT일 경우 연결 수락 작업 처리에서 필요한 ServerSocketChannel 얻는 코드 ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel(); |
작업 스레드가 채널 작업을 처리하다 보면 채널 객체 이외에 다른 객체가 필요하게 될 수 도 있습니다.
이런 객체는 SelectionKey 에 첨부해 두고 사용 가능합니다.
예)
[객체 첨부] Client client = new Client(socketChannel); SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_READ); selectionKey.attach(client); [첨부된 객체 얻기] if(selectionKey.isReadable()){ Client client = (Client)selectionKey.attachment(); ... } |
이상입니다.
다음 포스팅에서는 NIO TCP 넌블로킹 채널로 채팅 서버 구현에 대해 공부하겠습니다.
'자바' 카테고리의 다른 글
NIO TCP 비동기 채널의 특징, 비동기 채널 그룹 (0) | 2017.04.26 |
---|---|
자바 NIO TCP 넌블로킹 채팅 서버, 채팅 클라이언트 구현하기 Java Nonblocking chatting server, chatting server (0) | 2017.04.25 |
자바 NIO TCP 넌블로킹 채널 - 넌블로킹 방식의 특징, 셀렉터의 생성과 등록 (0) | 2017.04.21 |
자바 NIO TCP 블로킹과 인터럽트 (0) | 2017.04.20 |
자바 NIO TCP 블로킹 채널 클라이언트 구현하기 (0) | 2017.04.20 |