Java BIO,即blocking IO,是传统的Java IO编程,在JDK1.版本之前,只有这一种IO编程,BIO 相关的类和接口被封装在java.io包及其子包中。
BIO——同步阻塞型IO,每有一个客户端想要连接服务器时(即发出请求),服务器就启动一个线程专门处理该请求。一个连接对应一个线程,则有多少客户端连接服务器,就会产生多少线程。当有海量客户发出请求时,必然给服务器巨大的压力;除此之外,客户端对于服务器的访问并不是永久持续的,服务器在启动一个线程管理某客户端的请求后,客户端如果不再发送请求,那么这个线程就会被闲置,造成很多不必要的线程开销。
Java BIO可以通过线程池机制进行改善——实现多个客户连接服务器,但本质上额外开销的资源浪费的问题并没有解决。
BIO的简单工作流程:
- 服务器端启动一个ServerSocket
- 客户端启动一个Socket对服务器进行通信,默认情况下服务器对每一个客户建立一个线程与之通信。
- 客户端发出请求后,先咨询服务器是否有线程响应,若没有则等待/或被拒绝
- 若有响应,客户端线程等待当前请求结束后,执行下一个请求
以下是一个简单的基于BIO的C/S通讯程序:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 1)使用BIO编写一个服务器端,监听6666端口,当有客户端进行连接时,
* 就启动一个线程与之通信
* 2)使用线程池机制改善,可以连接多个客户端
* 3)服务器端可以接收客户端发来的数据(telnet方式即可)
* */
public class BIOserver {
public static void main(String[] args) throws IOException {
//线程池机制思路
//1、创建一个线程池
//2、如果有客户端连接,就创建一个线程,与之通讯(单独写一个方法)
ExecutorService executorService = Executors.newCachedThreadPool();
//创建ServerSocket
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服务器启动了");
while(true){
//监听、等待客户端连接
System.out.println("等待连接");
final Socket socket = serverSocket.accept();
System.out.println("连接到一个客户端");
//创建一个线程,与之通讯
executorService.execute(new Runnable() {
public void run() { //重写
//可以和客户端通讯
handler(socket);
}
});
}
}
//编写一个handler方法,与客户端通讯
public static void handler(Socket socket){
byte[] bytes = new byte[1024];
//通过socket获取一个输入流
try {
System.out.println("线程信息 id="+Thread.currentThread().getId() +
"name="+Thread.currentThread().getName());
InputStream inputStream = socket.getInputStream();
//循环读取客户端发送的数据
while (true){
System.out.println("线程信息 id="+Thread.currentThread().getId() +
"name="+Thread.currentThread().getName());
System.out.println("read......");
int read = inputStream.read(bytes);
if (read != -1){
System.out.println(new String(bytes,0,read)); //输出客户端发送的数据
}else { //读取完毕
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
System.out.println("关闭和Client的连接");
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行程序后,服务器启动并等待连接【阻塞】:
在cmd中输入telnet 127.0.0.1 6666,即模拟一个客户端向服务器发送了连接请求,服务器连接客户端,等待读取数据【阻塞】:
cmd中发送HelloWorld字符串到服务器:send HelloWorld