>  기사  >  Java  >  Java에서 논블로킹 I/O를 사용하는 방법

Java에서 논블로킹 I/O를 사용하는 방법

黄舟
黄舟원래의
2017-09-29 09:58:371480검색

이 기사에서는 주로 Java에서 비차단 I/O를 사용하는 방법을 소개합니다. 또한 비차단 I/O를 사용하여 클라이언트를 구현하는 방법도 보여줍니다. 필요하면 참고하시면 됩니다.

대부분의 지식과 예제는 O'REILLY의 "Java Network Programing, Fourth Edition, by Elliotte Rusty Harold(O'REILLY)"에서 나왔습니다.

비차단 I/O 소개

비차단 I/O(NIO)는 높은 동시성을 처리하는 수단입니다. 동시성이 높은 경우 스레드 생성 및 재활용, 스레드 간 전환에 따른 오버헤드가 무시할 수 없는 수준이 됩니다. 이때 Non-Blocking I/O 기술을 사용할 수 있습니다. 준비된 연결을 한번에 선택하고, 해당 연결이 관리할 수 있는 만큼의 데이터를 최대한 빠르게 채운 후 준비된 다음 연결로 이동하는 것이 이 기술의 핵심 아이디어이다.

비차단 I/O를 사용하여 구현된 클라이언트

일반적으로 클라이언트는 많은 수의 동시 연결을 처리할 필요가 없습니다. 실제로 비차단 I/O는 주로 서버용으로 설계되었지만 클라이언트에서도 사용할 수 있습니다. 클라이언트의 디자인은 서버의 디자인보다 쉽기 때문에 아래에서는 간단한 데모용으로 클라이언트를 사용하겠습니다.

먼저 channel과 버퍼를 소개합니다. SocketChannel 클래스는 비차단 I/O에서 연결을 생성하는 데 사용됩니다. SocketChannel 객체를 얻으려면 SocketAddress 객체(보통 해당 하위 클래스 InetSocketAddress)를 정적 팩터리 메서드 open()에 전달해야 합니다. 예를 들면 다음과 같습니다.


SocketAddress address = new InetSocketAddress("127.0.0.1", 19);
SocketChannel client = SocketChannel.open(address);

open() 메서드가 차단되므로 연결이 설정될 때까지 이후의 코드가 실행되지 않습니다. 연결을 설정할 수 없으면 IOException이 발생합니다.

연결이 설정된 후에는 입력과 출력을 얻어야 합니다. 전통적인 getInputStream() 및 getOutputStream()과 달리 채널을 사용하면 채널 자체에 직접 쓸 수 있습니다. 바이트 배열에 쓰는 대신 ByteBuffer 객체가 작성됩니다. ByteBuffer 객체는 ByteBuffer.allocate(int 용량)를 통해 얻습니다. 용량은 바이트 단위의 버퍼 크기입니다.


ByteBuffer buffer = ByteBuffer.allocate(74);

ByteBuffer 객체를 얻은 후 이를 SocketChannel 객체의 read() 메서드에 전달합니다. 소켓에서 읽은 데이터를 사용하여 이 버퍼를 채웁니다. read() 메서드는 성공적으로 읽고 버퍼에 저장된 바이트 수를 반환합니다. 기본적으로 최소 1바이트를 읽거나 -1을 반환하여 데이터 끝을 나타내고 사용 가능한 바이트가 없으면 차단됩니다. 이는 InputStream과 거의 동일한 방식으로 동작합니다. 그러나 비차단 모드로 설정된 경우 사용 가능한 바이트가 없으면 즉시 0을 반환하고 차단하지 않습니다.

이제 버퍼에 이미 일부 데이터가 있고 나중에 추출해야 한다고 가정합니다. 먼저 데이터를 바이트 배열에 쓴 다음 출력 스트림에 쓰는 전통적인 방법을 사용할 수 있습니다. 다음은 완전한 채널 기반 방법입니다. 채널 도구 클래스를 사용하여 출력 스트림을 채널로 캡슐화합니다.


WritableByteChannel out = Channels.newChannel(System.out);

위 코드는 System.out을 채널로 캡슐화합니다. 그 후에 출력이 이루어질 수 있습니다. ByteBuffer 객체의 각 출력 전에 채널이 처음부터 읽기 시작하도록 해당 Flip() 메서드를 호출해야 합니다. 읽고 쓴 후에는 버퍼의 상태를 재설정하기 위해 Clear() 메서드를 호출해야 합니다. 다음은 데이터 출력을 위한 코드입니다.


buffer.flip();
out.write(buffer);
buffer.clear();

예 1: 비차단 I/O를 사용하여 구현된 CharGenerator(문자 생성기) 클라이언트

서버 코드:


public static void createCharGeneratorServer(){
  try(ServerSocket server = new ServerSocket(19)){
    while(true){
      try(Socket connection = server.accept()){
        OutputStream out = connection.getOutputStream();
        int firstPrintableCharacter = 33;
        int numberOfPrintableCharacter = 94;
        int numberOfCharactersPerLine = 72;
        int start = firstPrintableCharacter;
        while(true){
          for(int i = start ;
              i < start + numberOfCharactersPerLine ; i++){
            out.write
            (firstPrintableCharacter + (i - firstPrintableCharacter) % numberOfPrintableCharacter);
          }
          out.write(&#39;\r&#39;);
          out.write(&#39;\n&#39;);
          start = firstPrintableCharacter + (start + 1 - firstPrintableCharacter) % numberOfPrintableCharacter;
        }
      }catch (IOException e) {
        e.printStackTrace();
      }
    }
  } catch (IOException e) {
    e.printStackTrace();
  }
}

클라이언트 코드:


try {
  SocketAddress address = new InetSocketAddress("127.0.0.1", 19);
  SocketChannel client = SocketChannel.open(address);
  ByteBuffer buffer = ByteBuffer.allocate(74);
    WritableByteChannel out = Channels.newChannel(System.out);
  while(client.read(buffer) != -1){
    buffer.flip();
    out.write(buffer);
    buffer.clear();
  }
} catch (IOException e) {
  e.printStackTrace();
}
输出(无限循环):
]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&&#39;()*+,-./0123456789:;<=>?@ABCDEF
^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&&#39;()*+,-./0123456789:;<=>?@ABCDEFG
_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&&#39;()*+,-./0123456789:;<=>?@ABCDEFGH
`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&&#39;()*+,-./0123456789:;<=>?@ABCDEFGHI
abcdefghijklmnopqrstuvwxyz{|}~!"#$%&&#39;()*+,-./0123456789:;<=>?@ABCDEFGHIJ
bcdefghijklmnopqrstuvwxyz{|}~!"#$%&&#39;()*+,-./0123456789:;<=>?@ABCDEFGHIJK

비차단 모드 활성화

위 프로그램은 입력/출력 스트림을 사용하는 전통적인 방식과 크게 다르지 않습니다. 그러나 ServerSocket의configureBlocking(false) 메소드를 호출하여 비차단 모드로 설정할 수 있습니다. 이 모드에서는 사용 가능한 데이터가 없으면 read() 메서드가 즉시 반환되어 클라이언트가 다른 작업을 수행할 수 있습니다. 그러나 데이터를 읽을 수 없으면 read() 메서드가 0을 반환하므로 데이터를 읽는 루프에 몇 가지 변경이 필요합니다.

위 내용은 Java에서 논블로킹 I/O를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.