자바 NIO 기본 사용
비 차단 의 의 미 는 하나의 스 레 드 를 사용 하여 대량의 데이터 연결 을 처리 할 수 있 고 '짧 은 데이터 긴 연결' 의 응용 장면, 예 를 들 어 인 스 턴 트 메 신 저 소프트웨어 에 매우 적합 하 다 는 것 이다.
차단 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();
}
}
그 밖 에 코드 를 더 잘 쓴 예 가 있 는데 참고 할 만하 다.
이 예 에서 클 라 이언 트 는 서버 에 메 시 지 를 보 내 고 서버 가 받 은 후에 클 라 이언 트 에 게 메 시 지 를 보 냅 니 다. 예 를 들 어 코드 도 의미 있 는 처 리 를 하지 않 았 지만 구조 가 합 리 적 이 므 로 이 를 바탕 으로 현실 응용 확장 개발 을 할 가치 가 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.