자바 NIO 기본 사용

8018 단어 자바nio
NIO 는 자바 가 제공 하 는 비 차단 I / O API 입 니 다.
비 차단 의 의 미 는 하나의 스 레 드 를 사용 하여 대량의 데이터 연결 을 처리 할 수 있 고 '짧 은 데이터 긴 연결' 의 응용 장면, 예 를 들 어 인 스 턴 트 메 신 저 소프트웨어 에 매우 적합 하 다 는 것 이다.
차단 C / S 시스템 에서 서버 는 모든 클 라 이언 트 연결 에 하나의 스 레 드 를 열 어 클 라 이언 트 가 보 내 는 메 시 지 를 차단 해 야 합 니 다. 만약 에 비 차단 기술 을 사용 하면 서버 는 하나의 스 레 드 로 연결 에 대해 문의 할 수 있 습 니 다. 기다 리 는 것 을 막 을 필요 가 없습니다. 이것 은 메모리 자원 의 낭 비 를 크게 줄 이 고 서버 가 클 라 이언 트 스 레 드 에서 계속 전환 하 는 데 가 져 온 CPU 소 모 를 피 할 수 있 습 니 다.서버 의 CPU 에 대한 효율 적 인 사용률 이 크게 높 아 졌 다.
 
그 핵심 개념 은 채널, 선택 기, 선택 키, 버퍼 를 포함한다.
Channel 은 I / O 채널 입 니 다. selector 를 등록 할 수 있 습 니 다. selection 작업 을 통 해 현재 채널 이 준비 되 어 있 는 차단 없 이 실행 할 수 있 는 동작 을 가 져 올 수 있 습 니 다. 이것 은 selection Key 에 의 해 표 시 됩 니 다.
SelectionKey 의 상수 필드 SelectionKey. OP * *채널 에 대응 하 는 몇 가지 동작, 예 를 들 어 connect (), accept (), read (), write ().
 
select 조작 후 selection Key. OP 획득WRITE 나 READ 는 Channel 에서 read 와 write 방법 을 차단 하지 않 고 호출 할 수 있 습 니 다. Channel 의 읽 기와 쓰기 동작 은 모두 Buffer 를 통 해 이 루어 져 야 합 니 다. 즉, 읽 기 는 데 이 터 를 채널 에서 Buffer 를 읽 은 다음 에 진일보 한 처 리 를 하 는 것 입 니 다. 쓰 기 는 먼저 데 이 터 를 Buffer 에 기록 한 다음 에 채널 에서 Buffer 를 받 아야 합 니 다.
 
다음은 NIO 를 사용 하 는 기본 C / S 예제 입 니 다. 이 예 는 기본 API 를 어떻게 사용 하 는 지 보 여주 기 위해 존재 합 니 다. 코드 의 건장 성, 합 리 성 은 참고 가치 가 없습니다.
이 예제 에 서 는 간단 한 C / S 를 구현 합 니 다. 클 라 이언 트 는 서버 에서 메 시 지 를 보 내 려 고 합 니 다. 서버 에서 받 은 메 시 지 를 콘 솔 에 인쇄 합 니 다. 실제 응용 프로그램 에 서 는 서버 가 메 시 지 를 분석 할 수 있 도록 데 이 터 를 보 내 는 프로 토 콜 을 정의 해 야 합 니 다. 이 예제 에 서 는 인 코딩 을 사용 하여 받 은 바이트 변환 문 자 를 무차별 적 으로 사용 하고 인쇄 합 니 다. 초기 분 배 된 ByteBuffer 의 용량 을 변경 합 니 다.인쇄 메시지 의 변 화 를 볼 수 있 습 니 다. 용량 이 작 을 수록 한 메시지 에 대한 처리 횟수 가 많 고 용량 이 크 면 더 적은 순환 횟수 에서 전체 메 시 지 를 읽 을 수 있 습 니 다. 그래서 정말 응용 장면 입 니 다. 적당 한 캐 시 크기 를 고려 하여 효율 을 높 여야 합 니 다.
서버
 
package hadix.demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * User: hAdIx
 * Date: 11-11-2
 * Time:   11:26
 */
public class Server {
    private Selector selector;
    private ByteBuffer readBuffer = ByteBuffer.allocate(8);//                  
    private Map<SocketChannel, byte[]> clientMessage = new ConcurrentHashMap<>();

    public void start() throws IOException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ssc.bind(new InetSocketAddress("localhost", 8001));
        selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        while (!Thread.currentThread().isInterrupted()) {
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = keys.iterator();
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                if (!key.isValid()) {
                    continue;
                }
                if (key.isAcceptable()) {
                    accept(key);
                } else if (key.isReadable()) {
                    read(key);
                }
                keyIterator.remove();
            }
        }
    }

    private void read(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();

        // Clear out our read buffer so it's ready for new data
        this.readBuffer.clear();

        // Attempt to read off the channel
        int numRead;
        try {
            numRead = socketChannel.read(this.readBuffer);
        } catch (IOException e) {
            // The remote forcibly closed the connection, cancel
            // the selection key and close the channel.
            key.cancel();
            socketChannel.close();
            clientMessage.remove(socketChannel);
            return;
        }

        byte[] bytes = clientMessage.get(socketChannel);
        if (bytes == null) {
            bytes = new byte[0];
        }
        if (numRead > 0) {
            byte[] newBytes = new byte[bytes.length + numRead];
            System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
            System.arraycopy(readBuffer.array(), 0, newBytes, bytes.length, numRead);
            clientMessage.put(socketChannel, newBytes);
            System.out.println(new String(newBytes));
        } else {
            String message = new String(bytes);
            System.out.println(message);
        }
    }

    private void accept(SelectionKey key) throws IOException {
        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
        SocketChannel clientChannel = ssc.accept();
        clientChannel.configureBlocking(false);
        clientChannel.register(selector, SelectionKey.OP_READ);
        System.out.println("a new client connected");
    }


    public static void main(String[] args) throws IOException {
        System.out.println("server started...");
        new Server().start();
    }
}

 그리고 클 라 이언 트.
 
package hadix.demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 * User: hAdIx
 * Date: 11-11-2
 * Time:   11:26
 */
public class Client {

    public void start() throws IOException {
        SocketChannel sc = SocketChannel.open();
        sc.configureBlocking(false);
        sc.connect(new InetSocketAddress("localhost", 8001));
        Selector selector = Selector.open();
        sc.register(selector, SelectionKey.OP_CONNECT);
        Scanner scanner = new Scanner(System.in);
        while (true) {
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            System.out.println("keys=" + keys.size());
            Iterator<SelectionKey> keyIterator = keys.iterator();
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                keyIterator.remove();
                if (key.isConnectable()) {
                    sc.finishConnect();
                    sc.register(selector, SelectionKey.OP_WRITE);
                    System.out.println("server connected...");
                    break;
                } else if (key.isWritable()) {

                    System.out.println("please input message");
                    String message = scanner.nextLine();
                    ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes());
                    sc.write(writeBuffer);
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new Client().start();
    }
}

 그 밖 에 코드 를 더 잘 쓴 예 가 있 는데 참고 할 만하 다.
이 예 에서 클 라 이언 트 는 서버 에 메 시 지 를 보 내 고 서버 가 받 은 후에 클 라 이언 트 에 게 메 시 지 를 보 냅 니 다. 예 를 들 어 코드 도 의미 있 는 처 리 를 하지 않 았 지만 구조 가 합 리 적 이 므 로 이 를 바탕 으로 현실 응용 확장 개발 을 할 가치 가 있 습 니 다.

좋은 웹페이지 즐겨찾기