자바 의 io 모델 상세 설명
우 리 는 먼저 자바 예 를 보 자.
package cn.bridgeli.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author bridgeli
*/
public class SocketBIO {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(9090, 20);
System.out.println("step1: new ServerSocket(9090) ");
while (true) {
Socket client = server.accept();
System.out.println("step2:client: " + client.getPort());
new Thread(new Runnable() {
@Override
public void run() {
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = client.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream));
while (true) {
String dataLine = reader.readLine(); // 2
if (null != dataLine) {
System.out.println(dataLine);
} else {
client.close();
break;
}
}
System.out.println(" ");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != reader) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null!= inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
}
}
BIO 는 최초의 IO 모델 로 이 모델 은 두 가지 큰 문제 가 있 습 니 다.1.accept 는 막 힌 것 입 니 다.2.read 도 차단 되 어 있 습 니 다.즉,우리 서버 가 일어나 면 accept 에서 차단 되 고 클 라 이언 트 연결 을 기다 리 지만 한 클 라 이언 트 가 연결 되 었 을 때 우 리 는 클 라 이언 트 로부터 데 이 터 를 읽 을 수 있 습 니 다.이때 도 차단 되 기 때문에 우리 의 시스템 은 단일 연결 일 수 밖 에 없습니다.여러 개의 클 라 이언 트 가 연결 되 었 을 때한 개 씩 줄 을 서서 연결 한 다음 에 클 라 이언 트 에서 데 이 터 를 읽 습 니 다.다 중 연결 을 실현 하기 위해 서 는 스 레 드 를 사용 하여 해결 해 야 합 니 다.처음에 클 라 이언 트 연결 을 기다 린 다음 에 클 라 이언 트 가 연 결 된 후에 스 레 드 를 시작 하여 클 라 이언 트 의 데 이 터 를 읽 은 다음 에 메 인 스 레 드 는 클 라 이언 트 연결 을 계속 기 다 려 야 합 니 다.이 모델 의 가장 큰 문 제 는 바로 탄력 적 인 신축 능력 이 부족 하 다 는 것 이다.클 라 이언 트 의 동시 방 문 량 이 증가 한 후에 서버 의 스 레 드 갯 수 와 클 라 이언 트 의 동시 방 문 량 은 1:1 의 정비례 관 계 를 나타 내 고 자바 중의 스 레 드 도 비교적 소중 한 시스템 자원 이다.스 레 드 수량 이 신속하게 팽창 한 후에 시스템 의 성능 이 급 격 히 떨 어 질 것 이다.방 문 량 이 계속 증가 하면 서 시스템 은 결국 죽 었 다.물론 자바 뿐만 아니 라 우 리 는 만 개의 클 라 이언 트 가 서버 에 연결 되 고 서버 가 만 개의 스 레 드 를 켜 야 한다 고 가정 합 니 다.그러면 이 럴 때 서버 가 스 레 드 만 켜 면 얼마나 많은 자원 을 차지 해 야 합 니까?메모리 가 얼마나 필요 합 니까?운영 체제 가 이 스 레 드 를 조정 하기 위해 CPU 도 다 점용 되 어야 합 니까?
이 문 제 를 해결 하기 위해 누군가가 서버 의 스 레 드 모델 을 최적화 시 키 고 서버 는 스 레 드 풀 로 여러 개의 클 라 이언 트 요청 을 처리 합 니 다.하지만 문제 가 있 습 니 다.
1.스 레 드 총수 가 제한 되 어 있 고 기 다 려 야 합 니 다.
2.남 은 연결 은 작업 대기 열 에 쌓 여 있 습 니 다.작업 대기 열 이 가득 찼 을 때 거부 정책 을 사용 하기 시 작 했 기 때문에 근본적으로 문 제 를 해결 하지 못 했 습 니 다.
2. NIO
BIO 의 가장 큰 문 제 는 B,block,차단 입 니 다.그래서 이 문 제 를 해결 하면 됩 니 다.이때 NIO 가 생 겨 났 습 니 다.N 은 non-block 이라는 뜻 입 니 다.
package cn.bridgeli.demo;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
/**
* @author bridgeli
*/
public class SocketNIO {
public static void main(String[] args) throws Exception {
LinkedList<SocketChannel> clients = new LinkedList<>();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(9090));
serverSocketChannel.configureBlocking(false);
while (true) {
SocketChannel client = serverSocketChannel.accept();
if (null != client) {
client.configureBlocking(false);
System.out.println("client port: " + client.socket().getPort());
clients.add(client);
}
ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
for (SocketChannel c : clients) {
int num = c.read(buffer);
if (num > 0) {
buffer.flip();
byte[] aaa = new byte[buffer.limit()];
buffer.get(aaa);
String b = new String(aaa);
System.out.println(c.socket().getPort() + " : " + b);
buffer.clear();
}
}
}
}
}
이 럴 때 우 리 는 연결 과 읽 기 가 모두 막 히 지 않 는 다 는 것 을 알 게 될 것 이다.모두 막 히 지 않 기 때문에 모든 연결 을 저장 하고 연결 에서 데 이 터 를 읽 기 위해 집합 이 필요 하 다.이 모델 은 우리 가 스 레 드 를 열 어야 하 는 문 제 를 해결 하고 한 번 도 순환 하지 않 았 습 니 다.만약 에 새로운 연결 이 오 면 우 리 는 연결 을 집합 에 넣 고 연결 중의 데 이 터 를 하나씩 읽 습 니 다.이 때 는 우리 가 모든 스 레 드 를 연결 할 필요 가 없습니다.그러나 문제 가 있 습 니 다.연결 이 증가 함 에 따라 우리 의 대기 열 은 점점 커 질 것 입 니 다.그리고 우 리 는 매번 모든 연결 을 옮 겨 다 니 며 데 이 터 를 읽 어야 합 니 다.우 리 는 만 개의 연결 이 있다 고 가정 합 니 다.그러나 앞의 9999 개의 연결 은 데이터 가 없고 마지막 연결 만 데이터 가 있 습 니 다.그 전에 9999 번 읽 는 것 은 낭비 입 니 다.3.다 중 재 활용
NIO 에서 읽 을 수 없 는 문 제 를 해결 하기 위해 서 이 때 우 리 는 사건 감청 에 따라 운영 체제 에 우리 가 그 사건 을 감청 한 다음 에 이 사건 들 이 데이터 가 도 착 했 을 때 우리 에 게 읽 으 라 고 알려 줄 수 있 습 니 다.예 는 다음 과 같 습 니 다.
package cn.bridgeli.demo;
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.Iterator;
import java.util.Set;
/**
* @author bridgeli
*/
public class SocketMultiplexingIO {
private ServerSocketChannel serverSocketChannel = null;
private Selector selector = null;
public void initServer() {
try {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(9090));
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
initServer();
System.out.println(" ...");
try {
while (true) {
while (selector.select() > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
acceptHandler(key);
} else if (key.isReadable()) {
readHandler(key);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void acceptHandler(SelectionKey key) {
try {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel client = ssc.accept();
client.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(8192);
client.register(selector, SelectionKey.OP_READ, buffer);
System.out.println(" :" + client.getRemoteAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
public void readHandler(SelectionKey key) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
buffer.clear();
int read = 0;
try {
while (true) {
read = client.read(buffer);
if (read > 0) {
buffer.flip();
while (buffer.hasRemaining()) {
client.write(buffer);
}
buffer.clear();
} else if (read == 0) {
break;
} else {
client.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SocketMultiplexingIO service = new SocketMultiplexingIO();
service.start();
}
}
다 중 재 활용 에 있어 서 poll,epoll,Selector 등 실현 방식 이 있 습 니 다.그 중에서 그들의 차 이 는 poll 은 우리 가 운영 체제 에 매번 어떤 사건 에 관심 을 가 져 야 하 는 지 알려 야 한 다 는 것 입 니 다.epoll 은 운영 체제 가 메모리 구역 을 열 어 우리 가 주목 해 야 할 일 을 저장 하고 매번 운영 체제 에 우리 가 어떤 사건 에 관심 을 가 지 는 지 알려 주지 않 아 도 됩 니 다.BIO,NIO,다 중 재 활용 에 대해 말 병사 교육 의 주지 레이 선생님 은 매우 형상 적 인 예 가 있다.BIO 는 막 혔 기 때문에 우리 가 모든 라인 을 연결 해 야 한다.이것 은 우리 가 모든 차 를 위해 톨 게 이 트 에서 길 을 건설 하 는 것 과 같다.모든 차 는 길 을 수리 해 야 한다.우 리 는 스스로 차 에서 짐 을 내 려 야 한다.NIO 가 막 히 지 않 으 면 우 리 는 매번 톨 게 이 트 에 달 려 가서 우리 가 수리 한 도로 위 에 차 가 왔 는 지,오지 않 았 는 지 를 봐 야 한다.다음 에 보고 오 면 우 리 는 화물 을 내리 고 다음 에 새로운 물건 이 있 는 지 없 는 지 를 기 다 려 야 한다.다 중 재 활용 중인 poll 은 바로 우리 가 톨 게 이 트 에 전화 기 를 설치 한 다음 에 우리 가 전 화 를 할 때마다 내 가 관심 을 가 지 는 어떤 길이 차 가 왔 는 지,내 가 짐 을 내 려 야 하 는 지 하 는 것 이다.epoll 은 우리 가 톨 게 이 트 에 전화 기 를 설치 할 뿐만 아니 라 우 리 는 공책 도 남 겼 다.우 리 는 전 화 를 할 때마다 우리 가 새로 관심 을 가 지 는 길 을 톨 게 이 트 에 알려 준다.톨 게 이 트 는 공책 에 우리 가 주목 하 는 그 길 들 을 적어 놓 았 다.만약 에 우리 가 만 개의 길 을 주목한다 고 가정 하면 우 리 는 매번 전화 로 이 만 개의 길 을 한쪽 으로 말 할 필요 가 없다.이 길 들 에 차 가 왔 는 지,우리 가 짐 을 내 려 야 하 는 지 물 어 볼 필요 가 없다.
마지막 으로 몇 가지 작은 문 제 를 말씀 드 리 겠 습 니 다.
1.우 리 는 IO 모델 을 배 웁 니 다.IO 모델 은 운영 체제 가 우리 에 게 제공 하 는 인터페이스 로 시스템 호출 에 속 하기 때문에 우 리 는 strace 를 통 해 모든 프로그램 이 실행 하 는 시스템 호출 을 추적 할 수 있 습 니 다.명령 은 다음 과 같 습 니 다.
strace -ff -o out +
2.우리 가 BIO 를 추적 할 때 JDK 의 최적화 로 인해 높 은 버 전의 JDK 를 사용 해도 차단 이 보이 지 않 습 니 다.이때 JDK 1.4 컴 파일 을 통 해 실행 할 수 있 습 니 다.(이것 도 우리 가 lambda 표현 식 과 try-with-resource 를 사용 하 는 이유 입 니 다)3.IO 호출 은 시스템 호출 에 속 하기 때문에 BIO->NIO->다 중 재 활용 은 운영 체제 의 발전 이다.그러나 우 리 는 각종 언어 로 쓰 인 것 이 응용 에 속 하기 때문에 비동기 비 차단 IO 모델 이 있 는 지 없 는 지 를 보면 운영 체제 의 밑바닥 에 이런 모델 이 있 는 지 없 는 지 를 볼 수 있다.운영 체제 가 우리 에 게 비동기 비 차단 IO 와 관련 된 인 터 페 이 스 를 제공 해 야 한다.우리 의 응용 만 이 한층 더 최적화 할 수 있다.
4.우 리 는 strace 를 통 해 추 적 된 모든 시스템 호출 을 통 해 man 명령 을 통 해 문 서 를 볼 수 있 습 니 다(Liux 시스템,비 Windows 시스템).man 명령 이 없 으 면 설치 하면 됩 니 다.
이상 은 자바 중의 io 모델 에 대한 상세 한 내용 입 니 다.자바 io 모델 에 관 한 자 료 는 우리 의 다른 관련 글 을 주목 하 세 요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.