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操作上,造成了线程资源的浪费。

原文地址:https://www.cnblogs.com/the-zym/p/14648200.html