Java NIO 시리즈 튜 토리 얼(6)Selector

8745 단어 javanio
Java NIO 시리즈 튜 토리 얼(6)Selector
링크 작성 자:Jakob Jenkov 방랑 교정:정 일
Selector(선택 기)는 자바 NIO 에서 여러 개의 NIO 채널 을 감지 할 수 있 고 읽 기와 쓰기 이벤트 와 같은 채널 이 준비 되 어 있 는 지 알 수 있 는 구성 요소 입 니 다.이렇게 하면 하나의 단독 스 레 드 는 여러 채널 을 관리 하여 여러 개의 네트워크 연결 을 관리 할 수 있다.
다음은 본 고 에서 언급 한 주제 목록 이다.
  • 왜 Selector 를 사용 합 니까?
  • Selector 의 생 성
  • Selector 에 채널 등록
  • SelectionKey
  • Selector 를 통 해 채널 선택
  • wakeUp()
  • close()
  • 완전한 예시
  • 왜 Selector 를 사용 합 니까?
    하나의 스 레 드 로 여러 채널 을 처리 하 는 것 은 채널 을 처리 하 는 데 더 적은 스 레 드 만 필요 하 다 는 것 이 장점 이다.사실상 모든 통 로 를 하나의 스 레 드 로 만 처리 할 수 있다.운영 체제 에 있어 스 레 드 간 컨 텍스트 전환 비용 이 매우 많 고 모든 스 레 드 는 시스템 의 일부 자원(예 를 들 어 메모리)을 점용 해 야 합 니 다.따라서 사용 하 는 스 레 드 가 적 을 수록 좋다.
    그러나 현대 의 운영 체제 와 CPU 가 다 중 태 스 크 에서 점점 더 잘 나타 나 기 때문에 다 중 스 레 드 의 비용 은 시간 이 지 날수 록 점점 작 아 졌 다 는 것 을 기억 해 야 한다.실제로 하나의 CPU 에 여러 개의 커 널 이 있다 면 다 중 태 스 크 를 사용 하지 않 는 것 은 CPU 능력 을 낭비 하 는 것 일 수 있다.어쨌든 그 디자인 에 관 한 토론 은 다른 글 에 넣 어야 한다.여기 서 는 selector 를 사용 하면 여러 채널 을 처리 할 수 있다 는 것 만 알 면 충분 하 다.
    다음은 단일 스 레 드 에서 selector 를 사용 하여 3 개의 channel 을 처리 하 는 예제 그림 입 니 다.
    Selector 생 성
    selector.open()방법 으로 selector 를 만 듭 니 다.다음 과 같 습 니 다.
    Selector selector = Selector.open();

    Selector 에 채널 등록
    Channel 과 Selector 를 함께 사용 하기 위해 서 는 채널 을 selector 에 등록 해 야 합 니 다.Selectable Channel.register()방법 으로 다음 과 같이 실현 합 니 다.
    channel.configureBlocking(false);
    SelectionKey key = channel.register(selector,
    	Selectionkey.OP_READ);

    Selector 와 함께 사용 할 때 채널 은 비 차단 모드 에 있어 야 합 니 다.이것 은 FileChannel 을 Selector 와 함께 사용 할 수 없다 는 것 을 의미한다.왜냐하면 FileChannel 은 비 차단 모드 로 전환 할 수 없 기 때문이다.소켓 채널 은 다 됩 니 다.
    register()방법의 두 번 째 매개 변 수 를 주의 하 십시오.셀 렉 터 를 통 해 채널 을 감청 할 때 어떤 사건 에 관심 이 있 었 는 지 를 뜻 하 는'interest 집합'이다.네 가지 서로 다른 유형의 사건 을 감청 할 수 있 습 니 다.
  • Connect
  • Accept
  • Read
  • Write

  • 채널 이 사건 을 촉발 시 켰 다 는 것 은 이 사건 이 이미 준비 되 었 다 는 것 을 의미한다.그래서 한 채널 이 다른 서버 에 성공 적 으로 연결 되 어'연결 완료'라 고 불 린 다.서버 socket channel 에서 새로 들 어 온 연결 을 받 을 준비 가 되 어 있 습 니 다."수신 완료"라 고 합 니 다.데이터 가 읽 을 수 있 는 채널 은'읽 을 준비 가 되 었 다'고 할 수 있다.데 이 터 를 쓰 기 를 기다 리 는 채널 은'쓰기 완료'라 고 할 수 있다.
    이 네 가지 사건 은 Selection Key 의 네 가지 상수 로 표시 합 니 다.
  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE

  • 한 가지 사건 에 만 관심 이 있다 면'비트 또는'연산 자 를 사용 하여 상수 로 연결 할 수 있 습 니 다.다음 과 같 습 니 다.
    int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

    다음은 interest 집합 에 대해 서도 계속 언급 하 겠 습 니 다.
    SelectionKey
    이전 소절 에서 selector 에 Channel 을 등록 할 때 register()방법 은 selection Key 대상 을 되 돌려 줍 니 다.이 대상 은 당신 이 관심 있 는 속성 을 포함 하고 있 습 니 다:
  • interest 집합
  • ready 집합
  • Channel
  • Selector
  • 추 가 된 대상(선택 가능)
  • 다음은 이 속성 들 을 설명 하 겠 습 니 다.
    관심 집합
    selector 에 채널 1 절 을 등록 하 는 것 처럼 interest 집합 은 당신 이 선택 한 관심 있 는 이벤트 집합 입 니 다.selection Key 를 통 해 interest 집합 을 읽 고 쓸 수 있 습 니 다.이렇게:
    int interestSet = selectionKey.interestOps();
    
    boolean isInterestedInAccept  = (interestSet & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT;
    boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;
    boolean isInterestedInRead    = interestSet & SelectionKey.OP_READ;
    boolean isInterestedInWrite   = interestSet & SelectionKey.OP_WRITE;

    "비트 와"로 interest 집합 과 주어진 Selection Key 상수 를 조작 하면 특정한 이벤트 가 interest 집합 에 있 는 지 확인 할 수 있 습 니 다.
    준비 집합
    ready 집합 은 채널 이 준 비 된 작업 의 집합 입 니 다.한 번 의 선택(Selection)후에 이 ready set 에 먼저 접근 할 것 입 니 다.selection 은 다음 소절 에서 설명 할 것 입 니 다.이렇게 ready 집합 에 접근 할 수 있 습 니 다:
    int readySet = selectionKey.readyOps();

    interest 집합 을 검사 하 는 것 과 같은 방법 으로 channel 에서 어떤 사건 이나 조작 이 이미 준비 되 었 는 지 검사 할 수 있 습 니 다.그러나 다음 네 가지 방법 을 사용 할 수 있 습 니 다.그들 은 모두 하나의 불 유형 으로 돌아 갑 니 다.
    selectionKey.isAcceptable();
    selectionKey.isConnectable();
    selectionKey.isReadable();
    selectionKey.isWritable();

    Channel + Selector
    Selection Key 에서 Channel 과 Selector 를 방문 하 는 것 은 간단 합 니 다.다음 과 같다.
    Channel  channel  = selectionKey.channel();
    Selector selector = selectionKey.selector();

    부가 대상
    한 대상 이나 더 많은 정 보 를 Selection Key 에 붙 일 수 있 으 며,주어진 채널 을 편리 하 게 식별 할 수 있다.예 를 들 어 채널 과 함께 사용 하 는 버 퍼 를 추가 하거나 데 이 터 를 모 은 대상 을 포함 할 수 있다.사용 방법 은 다음 과 같다.
    selectionKey.attach(theObject);
    Object attachedObj = selectionKey.p_w_upload();

    selector 에 채널 을 등록 할 때 대상 을 register()방법 으로 추가 할 수도 있다.예:
    SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);

    Selector 를 통 해 채널 선택
    Selector 에 하나 이상 의 채널 을 등록 하면 다시 불 러 오 는 select()방법 을 사용 할 수 있 습 니 다.이 방법 들 은 당신 이 관심 있 는 이벤트(예 를 들 어 연결,수용,읽 기,쓰기)가 준 비 된 채널 을 되 돌려 줍 니 다.다시 말 하면'읽 기 완료'채널 에 관심 이 있다 면 select()방법 은 읽 기 이벤트 가 준 비 된 채널 을 되 돌려 줍 니 다.
    다음은 select()방법:
  • int select()
  • int select(long timeout)
  • int selectNow()
  • select()적어도 하나의 통로 가 당신 이 등록 한 사건 에 준비 되 어 있 을 때 까지 막 혔 습 니 다.select(long timeout)는 select()와 마찬가지 로 최 장 시간 아웃 밀리초(인자)를 차단 합 니 다.selectNow()막 히 지 않 고 모든 채널 이 준비 되 어 있 으 면 바로 돌아 갑 니 다.이전 선택 작업 이후 선택 할 수 있 는 채널 이 없 으 면 이 방법 은 0 으로 돌아 갑 니 다.)
    select()방법 이 되 돌아 오 는 int 값 은 몇 개의 채널 이 이미 준비 되 었 는 지 를 나타 낸다.즉,지난번 에 select()방법 을 호출 한 후 몇 개의 채널 이 준비 상태 로 바 뀌 었 는 지 하 는 것 이다.select()방법 을 호출 하면 한 채널 이 준비 상태 가 되 어 1 을 되 돌려 줍 니 다.select()방법 을 다시 호출 하면 다른 채널 이 준비 되면 다시 1 을 되 돌려 줍 니 다.첫 번 째 로 준 비 된 channel 에 대해 아무런 조작 도 하지 않 았 다 면 지금 은 두 개의 준 비 된 채널 이 있 지만 매번 select()방법 호출 사이 에는 하나의 채널 만 준비 되 어 있 습 니 다.
    selectedKeys()
    select()방법 을 호출 하고 반환 값 은 하나 이상 의 채널 이 준비 되 었 음 을 나타 내 고 selector 의 selected Keys()방법 을 호출 하여'선택 한 키 집합(selected key set)'의 준비 채널 에 접근 할 수 있 습 니 다.다음 과 같다.
    Set selectedKeys = selector.selectedKeys();

    Selector 가 채널 을 등록 할 때 채널.register()방법 은 SelectionKey 대상 을 되 돌려 줍 니 다.이 대상 은 이 Selector 에 등록 하 는 통 로 를 대표 합 니 다.이 대상 들 은 Selection Key 의 selected KeySet()방법 으로 접근 할 수 있 습 니 다.
    선택 한 키 집합 을 옮 겨 다 니 며 준 비 된 채널 에 접근 할 수 있 습 니 다.다음 과 같다.
    Set selectedKeys = selector.selectedKeys();
    Iterator keyIterator = selectedKeys.iterator();
    while(keyIterator.hasNext()) {
        SelectionKey key = keyIterator.next();
        if(key.isAcceptable()) {
            // a connection was accepted by a ServerSocketChannel.
        } else if (key.isConnectable()) {
            // a connection was established with a remote server.
        } else if (key.isReadable()) {
            // a channel is ready for reading
        } else if (key.isWritable()) {
            // a channel is ready for writing
        }
        keyIterator.remove();
    }

    이 순환 은 선택 한 키 가 집 중 된 모든 키 를 옮 겨 다 니 며 각 키 에 대응 하 는 채널 의 준비 이 벤트 를 검사 합 니 다.
    매번 마지막 키 Iterator.remove()호출 에 주의 하 십시오.selector 는 선택 한 키 에서 selection Key 인 스 턴 스 를 집중 적 으로 제거 하지 않 습 니 다.통 로 를 처리 할 때 스스로 제거 해 야 합 니 다.다음 채널 이 준비 되면 selector 는 선택 한 키 에 다시 넣 습 니 다.
    Selection Key.channel()방법 으로 돌아 오 는 채널 은 ServerSocketChannel 이나 SocketChannel 등 처리 할 형식 으로 바 뀌 어야 합 니 다.
    wakeUp()
    어떤 스 레 드 가 select()방법 을 호출 한 후에 막 혔 습 니 다.채널 이 이미 준비 되 지 않 았 더 라 도 select()방법 으로 되 돌아 갈 방법 이 있 습 니 다.다른 스 레 드 가 첫 번 째 스 레 드 에서 select()방법 을 호출 하 는 대상 에서 selector.wakeup()방법 을 호출 하면 됩 니 다.select()방법 에 막 힌 스 레 드 는 바로 돌아 갑 니 다.
    다른 스 레 드 가 wakeup()방법 을 호출 했 지만 현재 스 레 드 가 select()방법 에 막 히 지 않 으 면 다음 select()방법 을 호출 하 는 스 레 드 는 즉시"깨 어 납 니 다(wake up)".
    close()
    Selector 를 사용 한 후 close()방법 을 사용 하면 이 Selector 를 닫 고 이 Selector 에 등 록 된 모든 SelectionKey 인 스 턴 스 를 무효 로 합 니 다.채널 자체 가 닫 히 지 않 습 니 다.
    완전한 예시
    여기 에는 하나의 완전한 예제 가 있 습 니 다.하나의 Selector 를 열 고 하나의 채널 을 등록 하여 이 Selector 에 등록 한 다음(채널 의 초기 화 과정 은 생략)이 Selector 의 네 가지 사건(수용,연결,읽 기,쓰기)이 준비 되 었 는 지 지속 적 으로 감시 합 니 다.
    Selector selector = Selector.open();
    channel.configureBlocking(false);
    SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
    while(true) {
      int readyChannels = selector.select();
      if(readyChannels == 0) continue;
      Set selectedKeys = selector.selectedKeys();
      Iterator keyIterator = selectedKeys.iterator();
      while(keyIterator.hasNext()) {
        SelectionKey key = keyIterator.next();
        if(key.isAcceptable()) {
            // a connection was accepted by a ServerSocketChannel.
        } else if (key.isConnectable()) {
            // a connection was established with a remote server.
        } else if (key.isReadable()) {
            // a channel is ready for reading
        } else if (key.isWritable()) {
            // a channel is ready for writing
        }
        keyIterator.remove();
      }
    }

    오리지널 문장,전재 설명: 자체 병렬 프로 그래 밍 망-ifeve.com
    본문 링크 주소: Java NIO 시리즈 튜 토리 얼(6)Selector

    좋은 웹페이지 즐겨찾기