BIO,全称是Blocking I/O(阻塞I/O),是Java中的一种传统IO操作模式,其相关的类和接口位于java.io
包中。BIO是一种同步并阻塞的IO模型,意味着当一个线程执行IO操作时,如果该操作未完成(例如,没有数据可读或没有写入数据的空间),该线程将一直等待,直到操作完成。
基于以上IO数据流转过程,BIO采用以下线程模型实现:
1. 工作机制
服务器端:
服务器端启动一个
ServerSocket
,绑定IP地址和端口,并启动监听。当有客户端连接请求时,服务器端需要为每个客户端连接启动一个新的线程(或从线程池中获取线程)来处理该连接。
客户端与服务器之间的数据交换(读/写操作)都是阻塞的,即一个线程在处理一个客户端连接时,必须等待读/写操作完成才能继续执行其他操作。
客户端:
客户端通过
Socket
与服务器建立连接。连接建立后,客户端与服务器之间的数据交换也是阻塞的。
2. 优缺点
优点:
代码简单直观:BIO模型的代码相对简单,易于理解和实现。
缺点:
资源消耗大:在并发连接数较多的情况下,需要为每个连接创建新的线程(或复用线程池中的线程),这会导致大量的线程上下文切换和内存消耗,从而影响系统性能。
扩展性差:随着并发连接数的增加,服务器端的性能将显著下降,因为线程资源是有限的。
响应慢:在单个线程处理多个连接时,如果某个连接上的操作阻塞了线程,那么其他连接上的操作也将被阻塞,导致整体响应速度变慢。
3. BIO的例子
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class BIOServer {
public static void main(String[] args) throws IOException {
// 监听端口
int port = 12345;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Server is running on port " + port);
while (true) {
// 等待客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("New client connected from " + clientSocket.getInetAddress().getHostAddress());
// 为每个客户端连接创建一个新的线程
new ClientHandler(clientSocket).start();
}
}
}
static class ClientHandler extends Thread {
private Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Received from client: " + inputLine);
out.println("Hello from server!");
if ("exit".equalsIgnoreCase(inputLine)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
评论区