一、重要概念
1. IO的分类
BIO(Blocking IO):同步阻塞式IO
NIO(New IO \ NonBlocking IO):同步非阻塞式IO
AIO(Async IO):异步非阻塞式IO
2. NIO的两个重要概念
Channel(信道):Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流,而且他们面向缓冲区的。
Selector(选择器): Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
二、ServerSocketChannel
//TestServer.java
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.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
public class TestServer {
public static void main(String[] args) throws InterruptedException {
try {
//1.创建信道
ServerSocketChannel ssc = ServerSocketChannel.open();
//2.为信道绑定端口号
ssc.bind(new InetSocketAddress(9000));
//3.设置该信道为非阻塞信道
ssc.configureBlocking(false);
//4.创建选择器
Selector selector = Selector.open();
//5.为信道注册该选择器
ssc.register(selector, SelectionKey.OP_ACCEPT);
//6.监听Selector
while(true) {
Thread.sleep(1000);
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if(key.isAcceptable()) {
SocketChannel channel = ssc.accept();
if(channel != null) {
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
if(key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
channel.read(byteBuffer);
byteBuffer.flip();
String str = Charset.forName("UTF-8").newDecoder().decode(byteBuffer).toString();
if(str.isEmpty()) {
continue;
}
System.out.println(str);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//TestClient.java
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class TestClient {
public static void main(String[] args) {
Socket socket;
PrintWriter pw;
try {
socket = new Socket("127.0.0.1", 9000);
pw = new PrintWriter(socket.getOutputStream());
pw.println("hello world");
pw.flush();
pw.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、DatagramChannel
//TestUDPServer.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class TestUDPServer {
public static void main(String[] args) {
DatagramChannel channel;
try {
channel = DatagramChannel.open();
channel.bind(new InetSocketAddress(9000));
ByteBuffer buffer = ByteBuffer.allocate(20);
buffer.clear();
channel.receive(buffer);
System.out.println("开始接收数据报文...");
System.out.println(new String(buffer.array()));
System.out.println("接收数据报文结束...");
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//TestUDPClient.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
public class TestUDPClient {
public static void main(String[] args) throws UnknownHostException, IOException {
DatagramSocket socket = new DatagramSocket(9001);
String string = "hello world";
byte[] buf = string.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length);
packet.setSocketAddress(new InetSocketAddress("127.0.0.1", 9000));
socket.send(packet);
socket.close();
}
}