关于阻塞与非阻塞:https://www.cnblogs.com/jhxxb/p/11272727.html
一、传统的 IO 流都是阻塞式的
当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。
因此,在网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
package nio; import org.junit.Test; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Scanner; public class TestBlockingNIO { // 客户端 @Test public void client() throws IOException { // 获取通道 SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); // 分配指定大小的缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); // 发送到服务端 Scanner scan = new Scanner(System.in); while (scan.hasNext()) { String str = scan.next(); buf.put(str.getBytes()); buf.flip(); sChannel.write(buf); buf.clear(); if ("exit".equals(str)) { break; } } // 接收服务端的反馈 sChannel.shutdownOutput(); int len = 0; while ((len = sChannel.read(buf)) != -1) { buf.flip(); System.out.println(new String(buf.array(), 0, len)); buf.clear(); } // 关闭通道 sChannel.close(); } // 服务端 @Test public void server() throws IOException { // 获取通道 ServerSocketChannel ssChannel = ServerSocketChannel.open(); // 绑定连接 ssChannel.bind(new InetSocketAddress(9898)); retry: while (true) { // 获取客户端连接的通道 SocketChannel sChannel = ssChannel.accept(); // 分配指定大小的缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); // 接收客户端的数据 while (sChannel.read(buf) != -1) { String str = new String(buf.array()).trim(); if ("exit".equals(str)) { break retry; } buf.flip(); System.out.println(str); buf.clear(); } // 发送反馈给客户端 buf.put("服务端接收数据成功!".getBytes()); buf.flip(); sChannel.write(buf); // 关闭通道 sChannel.close(); } // 关闭通道 ssChannel.close(); } }