NIO 구성 요소 Buffer, Channel 및 Selector
21552 단어 네트워크 프로그래밍
흐름과 NIO의 가장 중요한 차이점은 데이터가 포장되고 전송되는 방식이다. 원래의 I/O는 흐르는 방식으로 데이터를 처리하고 NIO는 블록으로 데이터를 처리한다.
흐름과 블록의 비교
버퍼
NIO의 데이터는 모두 채널에서 버퍼로 읽히고 버퍼에서 채널로 기록됩니다
버퍼는 본질적으로 데이터를 쓸 수 있고, 그 중에서 데이터를 읽을 수 있는 메모리이다.이 메모리는 NIO Buffer 개체로 포장되어 있으며 블록 메모리에 쉽게 접근할 수 있는 방법을 제공합니다
1. NIO의 Buffer는 다음과 같은 이점을 제공합니다.
이러한 버퍼 유형은 서로 다른 데이터 유형을 나타냅니다.다시 말하면char,short,int,long,float 또는double 형식을 통해 버퍼의 바이트를 조작할 수 있다
가장 핵심적인 것은 Byte Buffer이다. 앞에 있는 큰 종류는 포장만 했을 뿐이다. 우리가 가장 많이 사용하는 것도 Byte Buffer이다. Buffer를 하나의 수조로 이해할 수 있다. Int Buffer,Char Buffer,Double Buffer 등은 각각 int[],char[],double[] 등에 대응한다.
2. Buffer의 중요 속성:
capacity는 버퍼의 용량을 대표합니다. 변경할 수 없습니다.예를 들어capacity가 1024인 IntBuffer는 한 번에 1024개의 int 형식의 값을 저장할 수 있음을 나타낸다.Buffer의 용량이 capacity에 도달하면 Buffer를 비워야 다시 쓰기 가능
우선, 읽기와 쓰기 조작이라는 개념에 대해 먼저 설명해야 한다. 그렇지 않으면 혼동될 수 있다.시스템 수준:
Buffer의 경우:
position, 다음 쓰기 위치를 나타냅니다.초기값은 0입니다. 버퍼에 값을 쓸 때마다position은 자동으로 1을 추가하고, 읽을 때마다position은 자동으로 1을 추가합니다.
쓰기 모드에서 읽기 모드로 전환할 때 (flip),position은 0으로 돌아갑니다
limit, 쓰기 동작 모드에서 limit은 쓰기 가능한 최대 데이터를 대표합니다.이때limit은capacity와 같다.쓰기가 끝난 후 읽기 모드로 전환합니다. 이 때의 limit은 버퍼의 실제 데이터 크기와 같습니다. 버퍼가 가득 쓰여 있지 않기 때문입니다.
3. Buffer 객체 할당
Buffer 객체 초기화
ByteBuffer byteBuf = ByteBuffer.allocate(1024);
IntBuffer intBuf = IntBuffer.allocate(1024);
Buffer에 데이터 쓰기:
put 방법에 대해 다음과 같은 함수 정의가 있다
// byte
public abstract ByteBuffer put(byte b);
// int
public abstract ByteBuffer put(int index, byte b);
//
public final ByteBuffer put(byte[] src) {...}
이러한 방법은 스스로 버퍼의 크기를 조절해야 한다.capacity를 초과해서는 안 되고,java를 던질 줄 아는 것을 초과해서는 안 된다.nio.BufferOverflowException 예외
Channel을 사용하여 Buffer에 데이터를 씁니다. 시스템 차원에서 이 동작을 우리는 읽기 조작이라고 합니다. 왜냐하면 데이터는 외부 (파일이나 네트워크 등) 에서 메모리로 읽히기 때문입니다.
int bytesRead = inChannel.read(buf); // Buffer
Buffer에서 데이터를 읽습니다.Buffer의 값을 읽으려면 쓰기 모드에서 읽기 모드로 전환하고flip 방법은 Buffer를 쓰기 모드에서 읽기 모드로 전환합니다.flip () 방법은position을 0으로 설정하고limit을 이전position의 값, 즉 Buffer의 실제 데이터 크기로 설정합니다.
public final Buffer flip() {
limit = position; // limit
position = 0; // position 0
mark = -1;
return this;
}
get 방법은 여러 개를 다시 불러옵니다. 버퍼에서 다른 방식으로 데이터를 읽을 수 있습니다.
// position
public abstract byte get();
//
public abstract byte get(int index);
// Buffer
public ByteBuffer get(byte[] dst)
byte aByte = buf.get();
예를 들어 FileChannel을 통해 데이터를 파일에 쓸 수 있고 SocketChannel을 통해 데이터를 네트워크에 써서 원격 기기에 보낼 수 있다
int bytesWritten = channel.write(buf);
4. 중요한 방법
mark() and reset()
mark는position의 값을 임시로 저장하는 데 사용되며, 매번 mark () 방법을 호출할 때마다 mark의 값을 현재position으로 설정하여 나중에 필요할 때 사용합니다.뒤에 버퍼를 호출할 수 있습니다.reset () 방법으로 이position으로 복구
public final Buffer mark() {
mark = position;
return this;
}
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
rewind() clear() compact()
rewind ():position을 0으로 초기화합니다. 보통 Buffer를 처음부터 다시 읽는 데 사용됩니다.
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
clear (): 버퍼를 리셋합니다. 다시 실례화하는 것과 같습니다.position은 0으로 설정되고 limit은capacity의 값으로 설정됩니다.clear () 방법은 버퍼의 데이터를 비우지 않습니다. 다만 후속 쓰기는 원래의 데이터를 덮어쓰고 비우는 것과 같습니다.
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
compact (): 읽지 않은 데이터, 즉 포지션에서 limit 사이의 데이터 (읽지 않은 데이터) 를 처리하고, 읽지 않은 모든 데이터를 버퍼의 시작점으로 복사한 다음, 마지막 읽지 않은 요소의 다음 위치로 포지션을 설정하고, 이 기초에 다시 쓰기 시작합니다.이 때 limit은capacity와 같아서 새 데이터를 쓰면 원래 데이터를 덮어쓰지 않습니다
Channel
Channel은 데이터를 읽고 쓸 수 있는 객체입니다.NIO와 기존 I/O를 비교하면 채널이 흐름과 같습니다.Channel과 Buffer는 상호작용을 하며, 읽기 동작은 Channel의 데이터를 Buffer에 채우고, 쓰기 동작은 Buffer의 데이터를 Channel에 쓴다
NIO 구현 Channel:
channel.read(buffer);
channel.write(buffer);
FileChannel
FileChannel은 비차단 초기화를 지원하지 않습니다.
//
FileInputStream inputStream = new FileInputStream(new File("/data.txt"));
FileChannel fileChannel = inputStream.getChannel();
// RandomAccessFile
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
Buffer에서 파일 내용 읽기
ByteBuffer buffer = ByteBuffer.allocate(1024);
int num = fileChannel.read(buffer);
Channel에 파일 컨텐츠 쓰기
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(" Buffer ".getBytes());
// Buffer
buffer.flip();
while(buffer.hasRemaining()) {
// Buffer
fileChannel.write(buffer);
}
SocketChannel ServerSocketChannel
TCP 접속 채널
//
SocketChannel socketChannel = SocketChannel.open();
//
socketChannel.connect(new InetSocketAddress("https://www.javadoop.com", 80));
//
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 8080
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
while (true) {
// TCP , SocketChannel
SocketChannel socketChannel = serverSocketChannel.accept();
}
ServerSocketChannel은 Buffer와 접촉하지 않습니다. 데이터를 실제적으로 처리하지 않기 때문입니다. 요청을 받은 후에 SocketChannel을 실례화한 후에 이 연결 채널의 데이터 전달은 상관하지 않습니다. 포트를 계속 감청하고 다음 연결을 기다려야 하기 때문입니다.
3. Selector
선택기, Selector는 자바 NIO에서 여러 개의 NIO 채널을 감지하고, 읽기, 쓰기 이벤트와 같은 채널을 위한 준비가 되어 있는지 알 수 있는 구성 요소입니다.하나의 단독 라인으로 여러 개의 채널을 관리할 수 있어 여러 개의 네트워크 연결을 관리할 수 있다.Selector 는 다양한 I/O 이벤트에 대한 관심 분야를 등록하며, 이러한 이벤트가 발생하면 그 대상이 발생하는 이벤트를 알려줍니다.
// Selector
Selector selector = Selector.open();
// ,
channel.configureBlocking(false);
// Selector
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
register 방법의 두 번째 int형 매개 변수(이진법의 표시 위치를 사용)는 어떤 관심 있는 사건을 감청해야 하는지를 나타내는 데 사용된다. 총 네 가지 사건이다.
등록 메서드 반환 값은 SelectionKey 인스턴스이며 다음 항목을 포함합니다.
관련 방법
select () 방법, select () 방법이 되돌아오는 int값은 채널이 얼마나 준비되었는지 표시합니다.이 메서드를 사용하면 마지막 select 이후에 준비된 채널에 해당하는 SelectionKey를 selected set에 복사합니다.만약 어떤 통로가 준비되지 않았다면, 이 방법은 최소한 하나의 통로가 준비될 때까지 막힐 것이다
selectNow() 기능은 select와 마찬가지로 준비된 채널이 없으면 이 방법은 즉시 0으로 되돌아옵니다
select (long timeout) 채널이 준비되지 않으면 이 방법은 잠시 기다립니다
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Java 네트워크 프로그래밍의 간단한 서버 클라이언트 응용 사례본고는 자바 네트워크 프로그래밍의 간단한 서버 클라이언트 응용을 실례로 다루고 있다.여러분에게 참고할 수 있도록 나누어 드리겠습니다.구체적으로 다음과 같습니다. 우리는 소켓 클래스의 구조 함수를 사용하여 소켓을 열 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.