Netty核心原理解析(一) I/O模型之BIO模型原理讲解

一,I/O模型初识

所谓I/O模型,其实就是用什么样的通道对数据进行发送和接收,其很大的 程度上决定了当前陈程序通信的性能。
常见的有:
在这里插入图片描述
BIO: 同步并阻塞,具体实现模式: 一个请求连接对应一个线程,即客户端发送一个请求,服务器监听到之后,会给该请求创建独立的线程来进行处理。
NIO:同步非阻塞,具体实现模式:一个线程处理多个客户端请求,即客户端发送的请求会被注册到selector选择器上,通过selector选择器的select方法,多路复用轮询与客户端建立的连接通道,有事件响应就进行处理
AIO:异步非阻塞,相比前面两个引入了异步的概念,采用了Proactor模式,简化了程序编写,只有在有效的请求才启动线程去处理,特点: 首先由操作系统完成后,才通知服务端程序启动线程去处理,
注:(本篇主要讲解BIO模式,BIO,AIO就不延伸了)

二,应用场景

针对上面三种不同的模型,有不同的应用场景:
BIO:连接数较少且固定的架构,由于线程与请求一对一的关系,就导致对服务器的资源要求高,而且并发只能局限在应用中,JDK1.4之前的唯一选择
NIO:连接数多且连接时间短的架构(轻操作),比如,聊天服务器,弹幕系统及服务器之间的通讯(dubble的底层采用了netty组件,而netty就是基于NIO的模型),jdk 1.4开始支持
AIO:连接数目多且连接时间长的架构(重操作),比如相册服务器,文件下载等jdk7开始支持,但目前的应用市场小

三,BIO模型实例

为了加深理解,我们接下来分别写两个例子:
BIO实例:
要求:
1 使用BIO模型完成一个服务端,并监听指定端口,当有客户端进行连接时,就启动一个线程与之通信
2 优化,使用线程池机制优化,可以连接多个客户端
3 进阶,服务端可以接收客户端发送的数据并输出

package com.clcl.xxx.demo.CSDN.BIO;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

public class BIODemo {
    public static void main(String args[]) throws IOException {

        //创建线程池,用来处理客户端的请求
        ThreadPoolExecutor executor= new ThreadPoolExecutor(3,5,5, TimeUnit.SECONDS,new LinkedBlockingQueue<>(3), Executors.defaultThreadFactory(), new  ThreadPoolExecutor.AbortPolicy());
        //创建服务端的网络通信对象
        ServerSocket serverSocket=new ServerSocket();
        //绑定监听端口
        serverSocket.bind(new InetSocketAddress(6667));

        System.out.println("服务器启动了。。。");

        while(true){

            //等待客户端的连接
            //有连接,就会触发该方法,与客户端建立通信连接
            // ----如果没有链接就会阻塞,so 该方法为阻塞方法
            Socket socket = serverSocket.accept(); 
            //与客户端进行通信
            executor.execute(()->{
                //另写一个方法用来处理业务逻辑
                try {
                    System.out.println("线程"+Thread.currentThread().getName()+"与客户端"+socket.getRemoteSocketAddress()+"建立了连接"); 
                    handler(socket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }


  public  static void handler(Socket socket) throws IOException {
        //BIO以数据流的形式交换数据
        //通过socket获取输入流
         byte[] bytes=new byte[1024];
         InputStream stream = socket.getInputStream();
      try {
             //循环读取输入流
             while (true) {
                 //将输入流的数据读取到字节数组中
                 int read = stream.read(bytes);
                 //判断当前读取是否为空
                 if (read == -1) {
                     break;
                 }
                 //输出读取的数据
                 System.out.println("客户端发送的数据是:" + new String(bytes, 0, read));
             }
         }catch (Exception e){
             e.printStackTrace();
         }
         finally {
          stream.close();
          socket.close();
         }
    }
}

场景校验
通过客户端发送一个消息给服务端,查看服务端是否会打印数据?
客户端
客户端
服务端
在这里插入图片描述
结果
可以看到上面,客户端发送数据之后,服务端立马就接收到了数据,但是我们要如何证明在BIO模型下,一个请求是对应一个独立的线程呢?

代码解析BIO原理:
原理: 一个请求对应一个独立的线程。
场景: 启动多个客户端,并打印出每次与客户端通信的线程名称
客户端2
在这里插入图片描述
客户端3
在这里插入图片描述
服务端
在这里插入图片描述
结果可以发现,每来一个客户端请求,服务端都会启动一个独立的线程去处理,验证了 BIO模式下,一个请求对应一个独立的线程

再深入
BIO模型下的一些阻塞方法:
accept()
场景: 启动服务端,不做任何操作,可以发现,服务会一直阻塞在accept方法处
代码编辑: 在accept方法上下,添加标识

            System.out.println("执行accept方法前,,,");
            Socket socket = serverSocket.accept();
            System.out.println("执行accept方法后,,,");

启动服务端
在这里插入图片描述
结果: 可以发现,服务会一直阻塞在执行accept方法前,所以accept是个阻塞方法

read()
场景: 启动服务端,并创建一个客户端与之建立连接,不发送数据,查看服务是否会阻塞在read()方法
代码编辑:和上面一样,在read()方法上下添加标识

System.out.println("执行read方法之前");
                 int read = stream.read(bytes);
                 System.out.println("执行read方法之后");

服务端
在这里插入图片描述
结果: 可以发现,服务又阻塞在了read方法,于是可以得到read也是个阻塞方法。

BIO缺陷
看到这里可以发现BIO模型的一些缺陷:
1 每来一个客户端请求,服务端就要启动一个线程去执行读写事件,在客户端较多的情况下,对服务器的资源要求很高
2 在未与客户端建立请求时,主线程会一直阻塞在accept方法。
3 在与客户端建立请求之后,如果客户端未发送数据,那么该线程会一直阻塞在read方法,不能去执行其他任务,资源未被充分利用

好了,BIO模型到这里就算是解析完成了,后续下一篇会对NIO模型原理讲解,以上都是个人的一些看法,有不同滴看法或更好的意见,欢迎交流O(∩_∩)O

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值