자바 기반 NIO 소개 및 사용
java.nio 는 자바 non-blocking IO 라 고 합 니 다.jdk 1.4 및 이상 버 전에 서 제공 하 는 새로운 api(New IO)를 말 합 니 다.모든 원본 형식(boolean 형식 제외)에 캐 시 지원 데이터 용 기 를 제공 합 니 다.이 를 사용 하면 비 차단 식 고 신축성 네트워크 를 제공 할 수 있 습 니 다.
2,3 대 구성 요소
NIO 3 대 구성 요소:Channel,Buffer,Selector
1.Channel 과 Buffer
Channel 은 데 이 터 를 읽 고 기록 할 수 있 는 대상 입 니 다.NIO 를 원래 의 I/O 와 비교 하면 채널 은 마치 흐름 과 같 고 버퍼(Buffer)를 향 한 것 이다.모든 데 이 터 는 Buffer 대상 을 통 해 처 리 됩 니 다.채널 에 바이트 를 직접 쓰 지 않 고 하나 이상 의 바이트 가 포 함 된 버퍼 에 데 이 터 를 기록 합 니 다.채널 에서 바 이 트 를 직접 읽 지 않 고 채널 에서 버퍼 를 읽 고 버퍼 에서 이 바 이 트 를 가 져 옵 니 다.
Channel 은 데 이 터 를 읽 고 쓰 는 양 방향 채널 로 Channel 에서 데 이 터 를 Buffer 로 읽 을 수도 있 고 Buffer 의 데 이 터 를 Channel 로 쓸 수도 있 으 며 이전 Stream 은 입력(InputStream)이나 출력(OutputStream)으로 한 방향 으로 만 유통 된다.채널(Channel)은 읽 기,쓰기 또는 읽 기,쓰기 에 사용 할 수 있 습 니 다.
흔 한 채널
1.FileChannel
2.DatagramChannel
3.SocketChannel
4.ServerSocketChannel
Buffer 버퍼 는 데 이 터 를 읽 고 쓰 는 데 사 용 됩 니 다.흔히 볼 수 있 는 Buffer 입 니 다.
1.ByteBuffer
2.ShortBuffer
3.IntBuffer
4.LongBuffer
5.FloatBuffer
6.DoubleBuffer
7.CharBuffer
2.Selector
다 중 스 레 드 모드 에서 IO 를 막 을 때 한 스 레 드 는 http 요청 과 같은 요청 만 처리 할 수 있 습 니 다.요청 응답 식 으로 연결 을 닫 고 스 레 드 자원 을 방출 합 니 다.selector 선택 기의 역할 은 하나의 스 레 드 에 맞 춰 여러 채널 을 관리 하 는 것 입 니 다.이러한 채널 에서 발생 하 는 사건 을 가 져 오 는 것 입 니 다.이런 채널 작업 은 비 차단 모드 에서 스 레 드 를 한 채널 에 계속 두 지 않 고 연결 수가 매우 많 지만 데이터 가 낮은 장면 에 적합 합 니 다.
Selector 를 호출 하 는 select()방법 은 채널 에서 읽 기와 쓰기 가 완 료 된 이 벤트 를 보 낼 때 까지 막 힙 니 다.이 이벤트 들 이 발생 하면 select()방법 은
이 사건 들 을 thread 에 되 돌려 처리 합 니 다.
3.ByteBuffer 의 사용
속성:
Buffer 의 읽 기와 쓰기 동작 은 position,mark,limit 의 값 을 바 꾸 어 실현 하 는 것 입 니 다.그들 사이 의 관 계 를 주의 하면 쉽게 읽 고 쓰 고 덮어 쓸 수 있다.
Buffer 의 방법 은 모두 position 의 값 을 바 꾸 는 것 에 따라 조작 된다.
private static void buffer1() {
String data = "abc";
//byte[] bytes = new byte[1024];
// ,1024byte
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
System.out.println(byteBuffer.toString());
// position ,mark = position ,
System.out.println(byteBuffer.mark());
// , , , ,
System.out.println(byteBuffer.limit());
// , , ,
System.out.println(byteBuffer.position());
//capacity
System.out.println(byteBuffer.capacity());
// byteBuffer
byteBuffer.put(data.getBytes());
//
for(Byte b : byteBuffer.array()){
System.out.print(b + " ");
}
System.out.println();
System.out.println(new String(byteBuffer.array()));
// limit,position ,mark
byteBuffer.flip();
// ,
byteBuffer.put("n".getBytes()); // abc nbc
System.out.println(new String(byteBuffer.array()));
// position , mark() mark = position, position = mark,mark
byteBuffer.mark();
byteBuffer.reset();
// position mark , , /
byteBuffer.rewind();
for(Byte b : byteBuffer.array()){
System.out.print(b + " ");
}
System.out.println();
System.out.println(byteBuffer.toString());
// ,
byteBuffer.compact();
System.out.println(byteBuffer.toString());
}
쓰기 읽 기 전체 작업
private static void buffer(){
//
String data = "1234";
// ,1024byte
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
//
byteBuffer.put(data.getBytes());
// 49 50 51 52 0 0 0 0 0 0 0 0 0 0 0
println(byteBuffer.array());
byteBuffer.put((byte) 5);
// : 49 50 51 52 5 0 0 0 0 0 0 0 0 0 0
println(byteBuffer.array());
//
byteBuffer.flip(); // position = 0
byteBuffer.put((byte) 1);
byteBuffer.put((byte) 2);
byteBuffer.put((byte) 3);
byteBuffer.put((byte) 4);
byteBuffer.put((byte) 5);
// : 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0
println(byteBuffer.array());
//
byteBuffer.flip();//
while (byteBuffer.position() != byteBuffer.limit()){
System.out.println(byteBuffer.get());
}
// position limit
System.out.println(byteBuffer.toString());
//
byteBuffer.flip(); // position 0,
// byte ,
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.get(bytes);
// bytes 1 2 3 4 5
println(bytes);
}
private static void println(byte[] bytes){
for(Byte b : bytes){
System.out.print(b + " ");
}
System.out.println();
}
문자열 과 ByteBuffer 사이 의 변환
public static void main(String[] args) {
/*====================== buffer===========================*/
//1. buytebuffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("nio".getBytes());
//2.charset
ByteBuffer buffer1 = StandardCharsets.UTF_8.encode("nio");
//3, warp
ByteBuffer buffer2 = ByteBuffer.wrap("nio".getBytes());
/*======================buffer ===========================*/
String str = StandardCharsets.UTF_8.decode(buffer1).toString();
System.out.println(str);
}
5.채널 의 사용파일 프로 그래 밍 FileChannel
FileChannel 은 차단 모드 에서 만 작 동 할 수 있 습 니 다.Selector 에서 사용 할 수 없습니다.Channel 은 양 방향 채널 이지 만 FileChannel 은 원본 을 가 져 오 는 데 따라 읽 거나 쓸 수 있 습 니 다.
FileInputStream 가 져 오기,읽 기 전용FileOutputStream 가 져 오기,쓰기 만 가능
**
* Channel,FileChannel
* @throws Exception
*/
private static void channel() throws Exception{
FileInputStream in = new FileInputStream("C:\\Users\\zqq\\Desktop\\123.txt");
FileOutputStream out = new FileOutputStream("C:\\Users\\zqq\\Desktop\\321.txt");
// channel
FileChannel channel = in.getChannel();
// FileChannel
FileChannel outChannel = out.getChannel();
// byteBuffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// channel byteBuffer ,channel Buffer
while (channel.read(byteBuffer) != -1){
//position 0,
byteBuffer.flip();
outChannel.write(byteBuffer);
//byteBuffer
byteBuffer.clear();
}
//
channel.close();
out.flush();
out.close();
in.close();
out.close();
}
/**
* Channel
* @throws Exception
*/
public static void channel1() throws Exception{
// StandardOpenOption.READ : ,
// StandardOpenOption.WRITE : , ,
// StandardOpenOption.APPEND: , ,
// StandardOpenOption.CREATE: ,
// StandardOpenOption.CREATE_NEW: ,
// StandardOpenOption.DELETE_ON_CLOSE:
//
FileChannel inChannel = FileChannel.open(Paths.get("C:\\Users\\zqq\\Desktop\\123.txt"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("C:\\Users\\zqq\\Desktop\\321.txt"),
StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//
MappedByteBuffer inByteBuffer = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
MappedByteBuffer outByteBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
//
byte[] bytes = new byte[inByteBuffer.limit()];
inByteBuffer.get(bytes);// inByteBuffer , bytes
outByteBuffer.put(bytes);// outByteBuffer
inChannel.close();
outChannel.close();
}
RandomAccessFile 채널 열기
/**
* RandomAccessFile
* @throws Exception
*/
private static void random() throws Exception{
try (RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\workspace\\Demo\\test.txt","rw")){
// Channel
FileChannel fileChannel = randomAccessFile.getChannel();
//
//fileChannel.truncate(10);
// ByteBuffer,
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
fileChannel.read(byteBuffer);
System.out.println(new String(byteBuffer.array(),"GBK"));
byteBuffer.clear();
String data = "this is data\r";
byteBuffer.put(data.getBytes());
byteBuffer.flip();//
while (byteBuffer.hasRemaining()){
fileChannel.write(byteBuffer);
}
//
fileChannel.force(true);
}
}
FileChannel 데이터 전송 전송 전송
/**
* (copy)
*/
private static void transferTo() {
try (
FileChannel inChannel = new FileInputStream("C:\\Users\\44141\\Desktop\\demo\\in.txt").getChannel();
FileChannel outChannel = new FileOutputStream("C:\\Users\\44141\\Desktop\\demo\\out.txt").getChannel()
){
// , 。 2g
inChannel.transferTo(0,inChannel.size(),outChannel);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 2g
*/
private static void transferToGt2g() {
try (
FileChannel inChannel = new FileInputStream("C:\\Users\\44141\\Desktop\\demo\\in.txt").getChannel();
FileChannel outChannel = new FileOutputStream("C:\\Users\\44141\\Desktop\\demo\\out1.txt").getChannel()
){
// inChannel
long size = inChannel.size();
//
for(long rsize = size; rsize > 0;){
//transferTo
rsize -= inChannel.transferTo((size-rsize),rsize,outChannel);
}
}catch (Exception e){
e.printStackTrace();
}
}
네트워크 프로 그래 밍차단 모드
차단 모드 서버 의 모든 방법 은 클 라 이언 트 작업 을 기다 리 는 것 을 막 습 니 다.예 를 들 어 accept()방법 은 클 라 이언 트 연결 을 기다 리 는 것 을 막 고 read()방법 은 클 라 이언 트 가 데 이 터 를 전송 하 는 것 을 막 으 며 동시에 방문 하면 효율 적 인 작업 을 할 수 없습니다.
1.서버 코드
private static void server() throws Exception{
//1.
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2.
serverSocketChannel.bind(new InetSocketAddress(8080));
while (true){
System.out.println(" =============" );
//4.accept SocketChannel ,accept
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println(" ===============" );
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// read() ,
socketChannel.read(byteBuffer);
byteBuffer.flip();
String str = StandardCharsets.UTF_8.decode(byteBuffer).toString();
System.out.println(" =============:" + str);
}
}
2.클 라 이언 트 코드
private static void client() throws Exception {
//1.
SocketChannel socketChannel = SocketChannel.open();
//
socketChannel.connect(new InetSocketAddress("localhost",8080));
//2
Thread.sleep(2 * 1000);
socketChannel.write(StandardCharsets.UTF_8.encode("nio"));
System.out.println();
}
비 차단 모드서버 에서 비 차단 모드 로 설정 합 니 다.클 라 이언 트 는 움 직 이지 마 세 요.
private static void server() throws Exception{
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(8080));
while (true){
SocketChannel socketChannel = serverSocketChannel.accept();
// ,SocketChannel null
if(socketChannel != null){
//
socketChannel.configureBlocking(false);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
byteBuffer.flip();
String str = StandardCharsets.UTF_8.decode(byteBuffer).toString();
System.out.println(" =============:" + str);
}
}
}
7.선택 기Selector 선택 기의 역할 은 하나의 스 레 드 에 맞 춰 여러 채널 을 관리 하 는 것 입 니 다.Selector 가 관리 하 는 Channel 은 반드시 비 차단 모드 에서 이 루어 져 야 하기 때문에 Selector 는 FileChannel(FileChannel 은 차단 모드 만 있 음)과 함께 사용 할 수 없습니다.
선택 기 생 성
Selector 를 만 들 려 면 정적 방법 만 호출 하 십시오.
// Selector
Selector selector = Selector.open();
Selector 는 채널 의 이 벤트 를 감청 할 수 있 습 니 다.모두 네 개의 이벤트 가 있 습 니 다.accept:연결 요청 이 있 을 때 터치 합 니 다.정적 상수 Selection Key.OPACCEPT
//
serverSocketChannel.configureBlocking(false);
SelectionKey selectionKey = serverSocketChannel.register(selector,0,null);
//
selectionKey.interestOps(SelectionKey.OP_ACCEPT);
8.네트워크 프로 그래 밍(다 중 재 활용)1.클 라 이언 트 코드 SocketChannel
public static void main(String[] args) throws Exception {
client();
}
private static void client() throws Exception {
//1.
SocketChannel socketChannel = SocketChannel.open();
//
socketChannel.connect(new InetSocketAddress("localhost",8080));
//2
Thread.sleep(2 * 1000);
socketChannel.write(StandardCharsets.UTF_8.encode("nio"));
//3.
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
byteBuffer.flip();
System.out.println(" =======:" + StandardCharsets.UTF_8.decode(byteBuffer).toString());
//
socketChannel.close();
}
2.서버 코드
public static void main(String[] args) throws Exception{
server();
}
private static void server() throws Exception{
// Selector
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//
serverSocketChannel.configureBlocking(false);
// Channel selector ( )
// SelectionKey Channel
SelectionKey selectionKey = serverSocketChannel.register(selector,0,null);
//selectionKey ACCEPT ( )
selectionKey.interestOps(SelectionKey.OP_ACCEPT);
serverSocketChannel.bind(new InetSocketAddress(8080));
while (true){
System.out.println(" ====================");
// select ,
selector.select();
System.out.println(" =================");
//
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
SelectionKey sk = iterator.next();
// SelectionKey , (Selecotr )
iterator.remove();
// , ( ,selector.select() )
//sk.cancel();
//
if(sk.isAcceptable()){ //
// SelectionKey channel
ServerSocketChannel channel = (ServerSocketChannel) sk.channel();
SocketChannel socketChannel = channel.accept();
socketChannel.configureBlocking(false);
// ,bytebuffer ( )
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// socketChannel Selector
SelectionKey socketKey = socketChannel.register(selector,0,byteBuffer);
//
socketKey.interestOps(SelectionKey.OP_READ);
}else if(sk.isReadable()){//
try {
// Channel
SocketChannel socketChannel = (SocketChannel) sk.channel();
// ByteBuffer
ByteBuffer byteBuffer = (ByteBuffer) sk.attachment();
int read = socketChannel.read(byteBuffer);
// read = -1
if(read == -1){
//
sk.cancel();
continue;
}
byteBuffer.flip();
String str = StandardCharsets.UTF_8.decode(byteBuffer).toString();
System.out.println(" ===========:" + str);
//
ByteBuffer writeBuffer = StandardCharsets.UTF_8.encode("this is result");
socketChannel.write(writeBuffer);
// ( )
if(writeBuffer.hasRemaining()){
// , , interestOps() ( linux 777)
sk.interestOps(sk.interestOps() + SelectionKey.OP_WRITE);
sk.attach(writeBuffer);
//
//sk.interestOps(sk.interestOps() | SelectionKey.OP_WRITE);
}
}catch (IOException e){
e.printStackTrace();
// ,
sk.cancel();
}
}else if(sk.isWritable()){
// Channel
SocketChannel socketChannel = (SocketChannel) sk.channel();
// ByteBuffer
ByteBuffer writeBuffer = (ByteBuffer) sk.attachment();
socketChannel.write(writeBuffer);
// , , writeBuffer
if(!writeBuffer.hasRemaining()){
sk.attach(null);
//
sk.interestOps(sk.interestOps() - SelectionKey.OP_WRITE);
}
}
}
}
}
자바 기반 의 NIO 소개 및 사용 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 NIO 에 관 한 상세 한 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.