001-核心技术-IO模型简介、BIO简介及示例

一、概述

  基础:java编程、OOP编程、多线程、IO编程、网络编程、常用设计模式(观察者、命令、职责链等)、常用数据结构(链表等)

1.1、简介

  netty是一个java开源框架,是一个异步的,基于事件驱动的网络应用框架,用于快速开发高性能、高可靠性的网络IO程序。

  主要是针对在TCP协议下,面向Clients端的高并发应用,或者Peer-to-Peer场景下大量数据持续传输的应用。

  本质是一个NIO框架,适用于服务器通讯相关的多种应用场景。 

Netty
NIO【IO、网络】
JDK 原生IO[网络]
TCP/IP

1.2、应用场景

  互联网:在分布式系统中,各个节点之间需要远程服务调用,高性能的RPC框架不可缺少,Netty作为异步高性能的通讯框架,一般被作为基础通讯组件被RPC框架使用。

  典型应用:dubbo、网游、大数据[AVRO数据文件共享]、Akka、Flink、Spark

  书籍:Netty in action、netty 权威指南

二、IO模型

  IO模型简单理解:就是用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能

  java供支持3中网络编程模型IO模式:BIO、NIO、AIO

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

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

  AIO【NIO2.0】:异步非阻塞,AIO引入异步通道的概念,采用了Proactor模式,简化了程序编写,有效的请求才启动线程,他的特点是先有操作系统完成后成才通知服务端程序启动线程去处理,一般适用于连接数多且连接时间较长的应用。

        

三、BIO简介

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

3.1、编程流程

  1、服务器端启动一个ServerSocket

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

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

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

3.2、 应用实例

  1、监听6666端口,有连接启动线程

  2、使用线程池机制改善,可以连接多个客户端

  3、客户端使用telnet 测试

代码:

public class BIOServer {
    public static void main(String[] args) throws IOException {
        //1、创建一个线程池
        //2、客户端连接,启动一个线程

        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        ServerSocket serverSocket = new ServerSocket(6666);

        System.out.println("服务启动了:6666端口,telnet 127.0.0.1 6666");
        while (true) {
            System.out.println("等待连接……");
            final Socket socket = serverSocket.accept();

            System.out.println("一个客户端被连接");
            newCachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    handler(socket);
                }
            });
        }
    }

    public static void handler(Socket socket) {
        try {
            System.out.println("Thread id:" + Thread.currentThread().getId() +";name:"+ Thread.currentThread().getName());
            byte[] bytes = new byte[1024];
            //通过socket获取输入流
            InputStream inputStream = socket.getInputStream();
            //循环读取客户端数据
            while (true) {

                System.out.println("等待读取……");
                int read = inputStream.read(bytes);//将inputStream 读取到 bytes
                if (read != -1) {
                    System.out.println("Thread id:" + Thread.currentThread().getId() +";name:"+ Thread.currentThread().getName());

                    System.out.println("输出客户端发送的数据");
                    System.out.println(new String(bytes, 0, read));
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("关闭和client的连接");
            try {
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

测试 使用:

telnet 127.0.0.1 6666

3.3、BIO问题分析

  1、每个请求都需要创建独立的线程,与对应的客户端进行数据Read,业务处理,数据Write

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

  3、当连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在Read上,造成线程资源浪费 

 

posted @ 2020-07-01 13:40  bjlhx15  阅读(536)  评论(0)    收藏  举报
Copyright ©2011~2020 JD-李宏旭