java有三钟io模型:分别是BIO,NIO,AIO,
BIO
BIO: 同步阻塞型io. 传统的Socket编程即BIO, 一个连接需要一个线程处理.
基于BIO即 Socket实现的聊天demo
代码示例:
服务端:
package com.czy.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* BIO客户端,
* 支持多线程连接一个线程处理一个请求
*/
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
//2.服务端创建ServerSocket 对象 绑定服务端监听端口
ServerSocket serverSocket = new ServerSocket(9090);
while (true){
//3. 服务端 阻塞监听socket连接
Socket socket = serverSocket.accept();
executorService.execute(new Runnable() {
@Override
public void run() {
//4. 业务处理读取和写入数据
handle(socket);
}
});
}
}
private static void handle(Socket socket){
try {
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int read = inputStream.read(bytes);
System.out.println("客户端:"+new String(bytes,0,read,StandardCharsets.UTF_8));
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
OutputStream outputStream = socket.getOutputStream();
outputStream.write(s.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端:
package com.czy.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/**
* 客户端
*
*/
public class ClientDemo {
public static void main(String[] args) throws IOException {
while (true){
//1.创建Socket对象 绑定主机和端口,
Socket socket = new Socket("127.0.0.1",9090);
//2.创建输出流,便于后续socket向客户端发送数据
OutputStream outputStream = socket.getOutputStream();
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
// 3.向输出流中写入数据
outputStream.write(s.getBytes(StandardCharsets.UTF_8));
// 4.读取服务端发送的数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int read = inputStream.read(bytes);
System.out.println("服务端:"+new String(bytes,0,read,StandardCharsets.UTF_8));
// 5.关闭流
socket.close();
}
}
}
NIO
NIO简介:
同步非阻塞型io,一个线程处理多个连接请求,客户端发送的连接请求会注册到多路复用器上,多路复用器轮询到有IO请求的连接就进行处理
NIO三大核心概念的关系:
下图描述了NIO的Selector(选择器),Channel(通道)和Buffer(缓存区)的关系
1.一个客户端连接一个Channel,对应一个Buffer,
2.每条Channel都会注册到Selector上,Selector轮询Channel上事件,Selector根据不同的事件处理
3.Buffer本质上是数组,不同与BIO的是BIO只能读或者只能写,NIO的buffer是双向的,可读可写.
代码示例:基于NIO实现的聊天Demo: 该demo是未加Selector的编程的.有点繁杂,感兴趣的可以自行百度
客户端:
public class NIOClient {
public static void main(String[] args) throws IOException {
//1.打开通道
SocketChannel socketChannel = SocketChannel.open();
//2.绑定对应的端口
socketChannel.connect(new InetSocketAddress("127.0.0.1",9999));
//3.向缓冲区中写入数据
socketChannel.write(ByteBuffer.wrap("老板,还钱吧".getBytes(StandardCharsets.UTF_8)));
//4.申请缓冲区读取服务端信息
ByteBuffer allocate = ByteBuffer.allocate(1024);
int read = socketChannel.read(allocate);
System.out.println("服务端消息:"+new String(allocate.array(),0,read,StandardCharsets.UTF_8));
socketChannel.close();
}
}
服务端:
public class NIOServer {
public static void main(String[] args) throws IOException, InterruptedException {
//1.打开服务端通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2.绑定对应的端口号
serverSocketChannel.bind(new InetSocketAddress(9999));
//3.通道默认是阻塞的,需要设置成非阻塞
serverSocketChannel.configureBlocking(false);
System.out.println("服务端启动成功...");
while (true){
//4.检查是否有客户端连接, 有客户端连接会返回对应的通道
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel == null){
System.out.println("没有客户端连接...");
Thread.sleep(3000);
continue;
}
//5.获取客户端传递过来的数据,并将数据发在缓冲区中
ByteBuffer allocate = ByteBuffer.allocate(1024);
//返回值:正数本地没有读到有效字节数
//0:表示本地没有读到数据
//-1表示读到末尾
int read = socketChannel.read(allocate);
System.out.println("客户端消息: "+new String(allocate.array(),0,read, StandardCharsets.UTF_8));
//6.向客户端返会数据
socketChannel.write(ByteBuffer.wrap("没钱".getBytes(StandardCharsets.UTF_8)));
//7.关闭连接
socketChannel.close();
}
}
}
NIO与BIO的比较:
1.BIO是以流的方式处理数据的,而NIO以缓冲区的方式处理数据,缓冲区IO效率比流IO的效率高很多
2.BIO是阻塞的,NIO则是非阻塞的
3.BIO一个线程处理一个连接请求,而NIO有选择器可以实现单线程监听多个客户端连接.