概述

Netty其实就是一个异步的、基于事件驱动的框架,其作用是用来开发高性能、高可靠的IO程序。

因此下面就让我们从Java的IO模型来逐步深入学习Netty。

IO模型

IO模型简单来说,就是采用如何的方式来进行数据的接受和发送,因为存在着发送方和接收方两个角色,因此IO模型一般分为以下3类:BIO(同步阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)。其3者的区别如下:

  • BIO:是最传统的Java IO模型,采用的方式为服务器新接受到一个连接,就建立一个线程,但是如果这个连接不做任何事情,该线程也会被创建,闲置着,增加不必要的开销。
  • NIO:服务器用一个线程处理多个请求,将所有请求注册到一个线程管理的多路复用器(Selector)上。适用于连接数量多,但连接比较轻量的服务上,如聊天,弹幕等。
  • AIO:其特点是由OS完成后,才通知服务端程序启动程序来处理,使用场景为相册服务器等。因不是很清楚具体实现,因此在这不展开了。

BIO代码实现

使用BIO模型来实现一个服务器端和客户端,并采用线程池的概念,使其可以连接多个客户端。

服务端

首先,让我们来看建立一个服务端需要哪些步骤:

  1. // 创建线程池,如果有连接,就创建一个线程 ps:这里手动指定参数创建线程池会更好,但这里因为不是重点,因此就采用默认的线程池来实现。
  2. ExecutorService executorService = Executors.newCachedThreadPool();
  3. // create ServerSocket
  4. ServerSocket serverSocket = new ServerSocket(6666);
  5. System.out.println("服务端建立,监听!!!");
  6. while (true) {
  7. System.out.println("thread info0 id : " + Thread.currentThread().getId() + " \tname: " + Thread.currentThread().getName());
  8. // waiting for client
  9. System.out.println("等待客户端连接");
  10. // The method blocks until a connection is made.
  11. final Socket socket = serverSocket.accept();
  12. System.out.println("客户端连接成功");
  13. // create a thread for communicated
  14. executorService.execute(new Runnable() {
  15. @Override
  16. public void run() {
  17. handler(socket);
  18. }
  19. });
  20. }

上述代码就是一个服务器端启动的代码实例,那么该如何处理客户端发送的数据呢。

  1. public static void handler(Socket socket) {
  2. try (InputStream inputStream = socket.getInputStream();
  3. OutputStream outputStream = socket.getOutputStream();
  4. BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
  5. PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true)) {
  6. System.out.println("thread info1 id : " + Thread.currentThread().getId() + " \tname: " + Thread.currentThread().getName());
  7. String expression;
  8. String result;
  9. while (true) {
  10. System.out.println("thread info2 id : " + Thread.currentThread().getId() + " \tname: " + Thread.currentThread().getName());
  11. //BufferedReader.readLine()会读满缓冲区或者在读到文件末尾(遇到:"/r"、"/n"、"/r/n")才返回
  12. System.out.println("等待读取数据");
  13. if ((expression = bufferedReader.readLine()) == null) {
  14. break;
  15. }
  16. System.out.println("result: " + expression);
  17. }
  18. } catch (IOException e) {
  19. System.out.println(e);
  20. } finally {
  21. System.out.println("关闭和client连接!!!");
  22. try {
  23. socket.close();
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }

在这里我们采用循环读取的形式来处理客户端发送的数据,并将其进行输出。

客户端

  1. // 发送
  2. try (Socket socket = new Socket(InetAddress.getByName("localhost"), 6666);
  3. OutputStream outputStream = socket.getOutputStream()) {
  4. String data = "0A,3,863921030884418,23.178061,0,113.225998,0,2020/01/18 17:28:30,051,4,FF,";
  5. data = getData(data) + "\n";
  6. outputStream.write(data.getBytes());
  7. } catch (Exception e) {
  8. System.out.println(e);
  9. }

客户端的代码就很简单了,指定IP和端口,直接连接发送数据即可。

实现效果

首先我们启动服务端,可以看到如下输出,说明服务端已经被启动起来了,等待客户端连接。

然后,我们启动客户端1,服务端会启动一个线程来接受并处理请求。

BIO实现问题

上述就是一个BIO程序实现的Demo版本,这也就是BIO的优点所在,其实现简单,代码逻辑也十分的简洁明了。但其有几个很重要的问题没有解决。

  1. 对应于每个请求都要创建一个来解决,即使有线程池的存在,也会造成很大的线程资源损耗;
  2. handler() 代码中,我们可以看到其是在线程里处理的,但如果线程创建完成后,发现没有数据需要读写,那么其则会阻塞在 read 操作中,影响性能。

正因为BIO有着这许多问题,因此Java官方在1.4后引入了NIO的概念,来完善Java的IO模型,因此,在这里我们只需要了解这种模型即可,知道其会产生什么问题以及产生的原因,接下里,我们把重点放在NIO上,而这也是Netty实现的基础。

备注

本文中代码已上传到GitHub上,地址为 https://github.com/wb1069003157/nettyPre-research ,欢迎大家来讨论,探讨。

文章在公众号「iceWang」第一手更新,有兴趣的朋友可以关注公众号,第一时间看到笔者分享的各项知识点,谢谢!笔芯!

Netty学习(1):IO模型之BIO的更多相关文章

  1. Netty学习之IO模型

    目录 1.1 同步.异步.阻塞.非阻塞     同步 VS 异步         同步         异步     阻塞 VS 非阻塞         阻塞         非阻塞     举例   ...

  2. Java IO模型:BIO、NIO、AIO

    Java IO模型:BIO.NIO.AIO 本来是打算直接学习网络框架Netty的,但是先补充了一下自己对Java 几种IO模型的学习和理解.分别是 BIO.NIO.AIO三种IO模型. IO模型的基 ...

  3. IO模型之BIO代码详解及其优化演进

    一.BIO简介 BIO是java1.4之前唯一的IO逻辑,在客户端通过socket向服务端传输数据,服务端监听端口.由于传统IO读数据的时候如果数据没有传达,IO会一直等待输入传入,所以当有请求过来的 ...

  4. 5月2日 python学习总结 IO模型

    IO模型 1.阻塞IO 2.非阻塞IO 3.多路复用IO 4.异步IO 一.阻塞IO blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了. 实际上,除非 ...

  5. [编织消息框架][网络IO模型]BIO

    既然跟网络内容有关就不得不学习网络IO模型,时代在进步,技术也在进步,采取使用那种网络IO模型就已经确定应用程序规模 阻塞IO(blocking IO) 在linux中,默认情况下所有的socket都 ...

  6. 聊聊Netty那些事儿之从内核角度看IO模型

    从今天开始我们来聊聊Netty的那些事儿,我们都知道Netty是一个高性能异步事件驱动的网络框架. 它的设计异常优雅简洁,扩展性高,稳定性强.拥有非常详细完整的用户文档. 同时内置了很多非常有用的模块 ...

  7. Netty学习笔记-入门版

    目录 Netty学习笔记 前言 什么是Netty IO基础 概念说明 IO简单介绍 用户空间与内核空间 进程(Process) 线程(thread) 程序和进程 进程切换 进程阻塞 文件描述符 文件句 ...

  8. Java三种IO模型和LinuxIO五种IO模型

    Java: https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/BIO-NIO-AIO.md https://github.co ...

  9. Netty学习(2):IO模型之NIO初探

    NIO 概述 前面说到 BIO 有着创建线程多,阻塞 CPU 等问题,因此为解决 BIO 的问题,NIO 作为同步非阻塞 IO模型,随 JDK1.4 而出生了. 在前面我们反复说过4个概念:同步.异步 ...

随机推荐

  1. # Okhttp解析—Interceptor详解

    Okhttp解析-Interceptor详解 Interceptor可以说是okhttp的精髓之一,Okhttp重写请求/响应.重试.缓存响应等操作,基本都是在各个Interceptor中完成的,上篇 ...

  2. HDU5179 beautiful number 题解 数位DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5179 题目大意: 给你一个数 \(A = a_1a_2 \cdots a_n\) ,我们称 \(A\) ...

  3. 【一起学源码-微服务】Ribbon 源码三:Ribbon与Eureka整合原理分析

    前言 前情回顾 上一篇讲了Ribbon的初始化过程,从LoadBalancerAutoConfiguration 到RibbonAutoConfiguration 再到RibbonClientConf ...

  4. ACID特性及幻读的理解

    事务是关系型数据库的重要特性.它是一个包含了一条或多条SQL语句的逻辑原子单元.一个事务包含的SQL要么全部提交,要么全部回滚. Oracle 官方文档中对事务的描述如下: A transaction ...

  5. 天梯 L2 链表去重

    L2-002 链表去重 (25 分) 给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉.即对每个键值 K,只有第一个绝对值等于 K 的结点被保留.同时,所有被删除的结点须被保存在另一 ...

  6. 命令别名设定:alias,unalias 历史命令:history

    1.别名设定举例 alias lm=‘ls -al | more’ 还可以取代现有指令 alias rm='rm -i' 查询现有别名 alias 取消别名 unalias lm 2.历史命令:his ...

  7. 1、纯python编写学生信息管理系统

    1.效果图 2.python code: class studentSys(object): ''' _init_(self) 被称为类的构造函数或初始化方法, self 代表类的实例,self 在定 ...

  8. 贪心 park

    来总结一道非常经典的好题 这一道题是通过贪心实现的 首先看到这一题的时间复杂度 n<=100000 需要一个比较玄学的做法 我们先假设把题干改成这个样子 一圈n个车位 停在每个车位都有一定的代价 ...

  9. MOS 常用链接地址

    主页面类  Exadata主页面 Exadata Database Machine and Exadata Storage Server Supported Versions (Doc ID 8888 ...

  10. python StringIO和ByteIO

    一.StringIO 1.作用:在内存在读写str # 导入模块 from io import StringIO # 实例化StringIO对象 str_io = StringIO() # 向内存中写 ...