I/O模型简单介绍
I/O 模型简单的理解:就是用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能。
BIO
同步并阻塞,服务器实现模式为一个连接对应一个线程,即客户端有连接请求的时候服务器端就需要启动一个线程来进行处理,如果这个连接不做任何事情,就会造成不必要的开销。
适用场景
BIO方式适用于连接数目较小且固定的架构,这种方式对服务器资源要求较高,JDK1.4以前的唯一选择,程序简单通俗易懂(ServerSocket和Socket)。
代码示例
下面展示一个简单的BIO 示例
。
public class BIOServer {
public static void main(String[] args) throws Exception{
//线程池机制来看bio的原理---每发送一个请求,服务端就会启动一个新的线程来与之通信
//1.创建线程池
//2.如果有客户端连接,就创建一个线程与之通讯(这里单独写一个方法)
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//创建ServerSocket
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服务器启动了。。。。。。");
//服务端 循环监听客户端请求
while (true){
//等待客户端连接(在阻塞)
System.out.println("等待客户端连接。。。。。。。。。。。");
final Socket socket = serverSocket.accept();
System.out.println("有客户端连接了。。");
//创建一个线程 与之通讯
cachedThreadPool.execute(new Runnable() {
public void run() { //重写run方法
//和客户端进行通讯 单独写方法
hanlder(socket);
}
});
}
}
//和客户端通讯,接受客户端的数据
public static void hanlder(Socket socket){
byte[] bytes = new byte[1024];
try {
//查看当前客户端连接之后,服务端创建的与之通讯的线程的基本信息,
// 验证是否每一个客户端请求都要开启一个线程
System.out.println("当前线程id="+ Thread.currentThread().getId()
+"===当前线程Name="+ Thread.currentThread().getName());
//通过socket获取输入流
InputStream inputStream = socket.getInputStream();
//循环读取客户端发送的数据,并输出
while (true){
//查看当前线程是不是与客户端通讯的线程
System.out.println("当前线程id="+ Thread.currentThread().getId()
+"===当前线程Name="+ Thread.currentThread().getName());
//读了read个字节(此时线程还是阻塞,因为客户端不发数据,服务端就阻塞在这里)
System.out.println("等待数据。。。。。。。。。。。");
int read = inputStream.read(bytes);
if(read != -1){
//还有数据没读取
System.out.println(new String(bytes,0,read));//输出客户端发送过来的数据
}else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
//关闭和client的连接
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
程序使用telnet进行通讯,操作步骤:win+R --> cmd --> telnet+服务器地址+服务端端口号 --> ctrl+] --> send+要发送的数据就OK。
未知命令处理方式:
有的电脑上默认未开启telnet服务,开启步骤:控制面板 --> 程序 --> 启用或关闭Windows功能 --> 加载完成后再TelNet Client选项前打勾,保存就OK。
执行截图
为了验证BIO是否是只要一个新的客户端请求就新建一个线程处理,我们在代码中加入输出(上方代码中已加入),再看看运行结果。
这次分两次(模拟两个客户端)发送请求给服务器端,看看处理两次数据请求的线程id和名字就知道是同一线程还是不同线程了。
由此可见,开启两个telnet客户端来给服务器端发送数据,服务器端是启用了两个线程来进行处理的。
共同进步