• Netty学习二:IO模型 BIO


    一、I/O模型的基本概念

        I/O模型的简单理解就是,用什么样的通道进行数据的发送和接受,很大程度上决定了程序通讯的性能。

        JAVA程序支持3种网络通信模型/IO模式:BIO、NIO、AIO

          BIO:同步并阻塞(传统阻塞模型),服务器的实现模式为一个连接一个线程,及客户端有连接请求时,服务器端需要启动一个线程进行处理,如果这个线程不做任何事情,就会造成不必要的线程开销。

          适用于连接数较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4之前的唯一选择,但程序简单理解。

          NIO:同步非阻塞,服务器的实现模式为,一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接由I/O请求就进行处理。

          适用于连接数目多而且连接比较短的架构,比如聊天室,弹幕系统,服务器之间的通讯等,编程比较复杂,JDK1.4开始支持。

          AIO(NIO.2):异步非阻塞(尚未进行广泛应用),AIO引入了异步通道的概念,采用了Proactor模式,简化了程序的编写,有效的请求才可以启动线程。特点是,先由操作系统完成后才通知服务端应用程序启动线程去进行处理

          适用于连接数较多且连接时间较长的应用,比如相册服务器,编程比较复杂,JDK1.7引入。

    二、BIO

        主要定义如上所示。BIO可以通过线程池的机制来进行改善。

        BIO编程的简单流程:

          1.服务端启动一个ServerSocket

          2.客户端启动一个Socket对服务器进行通讯,默认情况下服务器需要对每个客户建立一个线程与之通讯。

          3.客户端发起请求后,先咨询服务器是否有线程响应,如果没有则会等待或者直接拒绝

          4.如果有响应,客户端线程会等待请求结束后,再继续执行

        BIO本地测试时,客户端可以通过telnet发送请求,服务端代码如下

     1 package com.mytest.bio;
     2 
     3 import java.io.InputStream;
     4 import java.net.ServerSocket;
     5 import java.net.Socket;
     6 import java.util.concurrent.ExecutorService;
     7 import java.util.concurrent.Executors;
     8 
     9 public class BioServer {
    10 
    11     public static void main(String[] args) throws Exception {
    12 
    13         //1.创建一个线程池
    14         ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
    15 
    16         //2.如果有客户端连接,就创建一个线程,与之通信
    17         //创建ServerSocket
    18         ServerSocket serverSocket = new ServerSocket(6666);
    19 
    20         System.out.println("服务器已启动");
    21 
    22         while (true) {
    23             //监听,等待客户端连接
    24             final Socket socket = serverSocket.accept();
    25             System.out.println("连接到一个客户端");
    26 
    27             //创建一个线程与之通讯
    28             newCachedThreadPool.execute(new Runnable() {
    29                 public void run() {
    30                     //可以和客户端进行通讯
    31                     handler(socket);
    32                 }
    33             });
    34         }
    35     }
    36 
    37     //编写一个handler方法,和客户端进行通讯
    38     public static void handler(Socket socket) {
    39         try {
    40             System.out.println("线程信息 id=" + Thread.currentThread().getId() + "名字=" + Thread.currentThread().getName());
    41             byte[] bytes = new byte[1024];
    42             //通过socket获取输入流
    43             InputStream inputStream = socket.getInputStream();
    44             //循环读取客户端发送的数据
    45             while (true) {
    46                 System.out.println("线程信息 id=" + Thread.currentThread().getId() + "名字=" + Thread.currentThread().getName());
    47                 int read  = inputStream.read(bytes);
    48                 if (read != -1) {
    49                     System.out.println(new String(bytes, 0, read));
    50                 }else {
    51                     break;
    52                 }
    53             }
    54         }catch (Exception e) {
    55             e.printStackTrace();
    56         }finally {
    57             //无论处理结果如何,都需要关闭socket
    58             System.out.println("关闭和client的连接");
    59             try{
    60                 socket.close();
    61             }catch (Exception e) {
    62                 e.printStackTrace();
    63             }
    64         }
    65     }
    66 }

        BIO存在的问题:

          1.每个请求都会创建独立的线程,与对应的客户端进行read/write

          2.当并发数较大时,需要创建大量的线程来处理连接,系统资源占用较大

          3.连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在read操作上,造成了线程资源的浪费。

  • 相关阅读:
    元组转换列表
    python切片
    序列类型的方法 增删改查
    python基础 四则运算和数据类型
    linux 常用基础命令操作
    MySQL 命令操作
    linux中如何修改root密码、设置固定IP、安装vmware tools
    虚拟机中网络桥接模式设置
    PHP基础
    HTML基本标签介绍
  • 原文地址:https://www.cnblogs.com/the-zym/p/14648200.html
Copyright © 2020-2023  润新知