java.io最为核心的一个概念是流(stream),面向流的编程,在java中,一个流要么是输入流,要么是输出流。
java.nio中拥有三个核心概念,selector,channel和buffer,在Java.nio中我们是面向块(block)或是缓冲区(buffer)编程的,buffer本身就是一块内存,底层实现上,实际就是一个数组,数据的读写都是通过buffer来实现的。
除了数组外,buffer还提供了对于数据的结构化访问方式,并且可以追踪到系统的读写过程。
java中7中原生数据类型(除了boolean)都有各自的buffer类型,如IntBuffer,ByteBuffer和CharBuffer等。
channel指的是可以向其写入数据或者从中读取数据的对象,它类似java.io中的stream。
所有数据的读写都是通过buffer来进行的,永远不会出现数据直接向channel中写入数据的情况,或者直接从channel中读取数据。
与stream不同的是channel是双向的,一个流只可能是inputStream或者outputStream,
案例
package com.kkagr.nio;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NioTest2 {
public static void main(String[] args) throws Exception{
FileInputStream fileInputStream = new FileInputStream("NioTest2.text");
FileChannel fileChannel = fileInputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
fileChannel.read(byteBuffer);
byteBuffer.flip();
while (byteBuffer.remaining()>0){
byte b = byteBuffer.get();
System.out.println("character:"+(char)b);
}
fileInputStream.close();
}
}
package com.kkagr.nio;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NioTest3 {
public static void main(String[] args) throws Exception{
FileOutputStream fileOutputStream = new FileOutputStream("NioTest3.txt");
FileChannel fileChannel = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
byte[] messages = "hello world welcome,nihao".getBytes();
for(int i = 0;i<messages.length;++i){
byteBuffer.put(messages[i]);
}
byteBuffer.flip();
fileChannel.write(byteBuffer);
fileOutputStream.close();
}
}
package com.kkagr.nio;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NioTest4 {
public static void main(String[] args) throws Exception{
FileInputStream inputStream = new FileInputStream("NioTest2.text");
FileOutputStream outputStream = new FileOutputStream("NioTest4.text");
FileChannel inputChannel = inputStream.getChannel();
FileChannel outputChannel = outputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(2);
while(true){
byteBuffer.clear();
int read = inputChannel.read(byteBuffer);
System.out.println(read);
if(-1 ==read){
System.out.println("over");
break;
}
byteBuffer.flip();
outputChannel.write(byteBuffer);
}
inputChannel.close();
outputChannel.close();
}
}
等待数据制定字符数,然后回显
package com.kkagr.nio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
public class NioTest11 {
public static void main(String[] args) throws Exception{
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress(8899);
serverSocketChannel.socket().bind(address);
int messageLenth = 2+3+4;
ByteBuffer[] byteBuffers = new ByteBuffer[3];
byteBuffers[0] = ByteBuffer.allocate(2);
byteBuffers[1] = ByteBuffer.allocate(3);
byteBuffers[2] = ByteBuffer.allocate(4);
SocketChannel socketChannel = serverSocketChannel.accept();
while(true){
int byteRead = 0;
while(byteRead < messageLenth){
long r = socketChannel.read(byteBuffers);
byteRead +=r;
System.out.println("byteRead:"+byteRead);
Arrays.asList(byteBuffers).stream().
map(buffer ->"positin:"+buffer.position()+",limit"+buffer.limit()).
forEach(System.out::println);
}
Arrays.asList(byteBuffers).forEach(byteBuffer -> {
byteBuffer.flip();
});
long byteWritten = 0;
while (byteWritten < messageLenth){
long r = socketChannel.write(byteBuffers);
byteWritten+=r;
}
Arrays.asList(byteBuffers).forEach(byteBuffer -> {
byteBuffer.clear();
});
System.out.println("bytesRead:"+byteRead+",byteWriteen:"+byteWritten+",messageLenth"+messageLenth);
}
}
}
selector特性,一个selector多个channel
package com.kkagr.nio;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;
public class NioTest12 {
public static void main(String[] args) throws Exception{
int[] ports = new int[5];
ports[0]=5000;
ports[1]=5001;
ports[2]=5002;
ports[3]=5003;
ports[4]=5004;
Selector selector = Selector.open();
for(int i =0 ;i< ports.length;i++){
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
InetSocketAddress address = new InetSocketAddress(ports[i]);
serverSocket.bind(address);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("监听端口:"+ports[i]);
}
while (true){
int numbers = selector.select();
System.out.println("numbers:"+numbers);
Set<SelectionKey> selectionKeys = selector.selectedKeys();
System.out.println("selectionkeys:"+selectionKeys);
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
if(selectionKey.isAcceptable()){
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ);
iterator.remove();
System.out.println("获得客户端连接:"+socketChannel);
}else if(selectionKey.isReadable()){
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
int byteRead = 0;
while(true){
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
byteBuffer.clear();
int read = socketChannel.read(byteBuffer);
if(read <= 0){
break;
}
byteBuffer.flip();
socketChannel.write(byteBuffer);
byteRead+=read;
}
System.out.println("读取:"+byteRead+",来自:"+socketChannel);
iterator.remove();
}
}
}
}
}
使用nio进行多客户端聊天
package com.kkagr.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class NioServer {
public static Map<String,SocketChannel> clientMap = new HashMap<>();
public static void main(String[] args) throws Exception{
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(8899));
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true){
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
selectionKeys.forEach(selectionKey -> {
final SocketChannel client;
try {
if(selectionKey.isAcceptable()){
ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
client = server.accept();
client.configureBlocking(false);
client.register(selector,SelectionKey.OP_READ);
String key = "["+ UUID.randomUUID().toString()+"]";
clientMap.put(key,client);
}else if(selectionKey.isReadable()){
client = (SocketChannel)selectionKey.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int count = client.read(readBuffer);
if(count>0){
readBuffer.flip();
Charset charset = Charset.forName("utf-8");
String receiveMessage = String.valueOf(charset.decode(readBuffer).array());
System.out.println(client+":"+receiveMessage);
String senderKey = null;
for(Map.Entry<String,SocketChannel> entry:clientMap.entrySet()){
if(client == entry.getValue()){
senderKey = entry.getKey();
break;
}
}
for(Map.Entry<String,SocketChannel> entry:clientMap.entrySet()){
SocketChannel value = entry.getValue();
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
writeBuffer.put((senderKey+":"+receiveMessage).getBytes());
writeBuffer.flip();
value.write(writeBuffer);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
selectionKeys.clear();
}
}
}
使用客户端代码
package com.kkagr.nio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.time.LocalDateTime;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NioClient {
public static void main(String[] args) {
try {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
Selector selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_CONNECT);
socketChannel.connect(new InetSocketAddress("127.0.0.1",8899));
while(true){
selector.select();
Set<SelectionKey> ketSet = selector.selectedKeys();
for(SelectionKey selectionKey:ketSet){
if(selectionKey.isConnectable()){
SocketChannel client = (SocketChannel) selectionKey.channel();
if(client.isConnectionPending()){
client.finishConnect();
ByteBuffer writeByffer = ByteBuffer.allocate(1024);
writeByffer.put((LocalDateTime.now()+"连接成功").getBytes());
writeByffer.flip();
client.write(writeByffer);
ExecutorService executorService = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
executorService.submit(()->{
while(true){
try {
writeByffer.clear();
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(input);
String sendMessage = br.readLine();
writeByffer .put(sendMessage.getBytes());
writeByffer.flip();
client.write(writeByffer);
} catch (IOException e) {
e.printStackTrace();
}
}
});
; }
client.register(selector,SelectionKey.OP_READ);
}else if(selectionKey.isReadable()){
SocketChannel client = (SocketChannel) selectionKey.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int count = client.read(readBuffer);
if(count>0){
String readMessage = new String(readBuffer.array(),0,count);
System.out.println(readMessage);
}
}
}
ketSet.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}