阻塞与非阻塞
传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户
使用NIO完成网络通信
阻塞式:
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class BlockingNIOTest {
@Test
public void client() throws IOException {
//获取通道
SocketChannel sChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
FileChannel inChannel=FileChannel.open(Paths.get("文件路径"),StandardOpenOption.READ);
//分配指定大小的缓冲区
ByteBuffer buf=ByteBuffer.allocate(1024);
//读取本地文件,并发送到服务器
while (inChannel.read(buf)!=-1){
buf.flip();
sChannel.write(buf);
buf.clear();
}
//关闭通道
sChannel.close();
inChannel.close();
}
@Test
public void server() throws IOException {
//获取通道
ServerSocketChannel ssChannel=ServerSocketChannel.open();
FileChannel outChannel=FileChannel.open(Paths.get("文件路径"),StandardOpenOption.READ,StandardOpenOption.CREATE);
//绑定9898端口连接
ssChannel.bind(new InetSocketAddress(9898));
//获取客户端连接的通道
SocketChannel socketChannel=ssChannel.accept();
//分配指定大小的缓冲区
ByteBuffer buf=ByteBuffer.allocate(1024);
//接收客户端的数据,并报错到本地
while (socketChannel.read(buf)!=-1){
buf.flip();
outChannel.write(buf);
buf.clear();
}
//关闭通道
outChannel.close();
ssChannel.close();
socketChannel.close();
}
}