公司的一些项目采用了netty框架,为了加速适应公司开发,本博主认真学习netty框架,前一段时间主要看了看书,发现编程这东西,不上手还是觉得差点什么,于是为了加深理解,深入学习,本博主还是决定多动手,一方面记录一些总结性的思考性东西,另一方面也为日后复习查看留下一些东西。

  那么废话少说,现在开始,首先在进入netty学习之前,我们是要认识一下IO并引出NIO的概念。

  与IO相关的几种编程及特点分为:

编程类别 特点
传统BIO编程

典型的一请求一应答模型,一个请求新建一个线程,应答完成线程销毁,线程个数和客户端并发访问呈现1:1的正比关系,当线程数膨胀之后,虚拟机性能下降明显,随着并发量继续增大,线程耗尽就会出现线程堆栈溢出,创建新线程失败,并最终宕机。该模型无法满足高性能高并发的场景。

伪异步IO编程

伪异步IO是对BIO的优化,引入线程池和消息队列,改善了传统BIO编程,但是其底层仍然是BIO模型,该模型引入线程池后界定了线程的数量,N个线程处理M个客户端请求,M可以远远大于N,线程池灵活调配线程资源,有最大线程数限制,避免了一个客户端请求创建一个线程的弊端,不会发生高并发访问下的线程资源耗尽而造成堆栈溢出或宕机的问题。

其不利因素是当一个客户端请求没有处理完成时,如IO读写或网络慢时,会造成任务队列中的任务一直处于等待状态,被阻塞了。当线程池中所有线程都满程处于阻塞状态时,就无法接收客户端新的请求,请求总是超时,此时可以认为是系统崩溃。

NIO编程

NIO模型引入了缓冲区Buffer,所有数据的读写都是用缓冲区处理的。引入channel通道,和selector多路复用器。

客户端发起的连接操作是异步的,可以通过在多路复用器注册OP_CONNECT等待后续结果,不需要像之前的客户端那样被同步阻塞,

socketchannel的读写都是一步的,如果没有可以读写的数据他不会同步等待,直接返回,这样I/O通信线程就可以处理其他的链路,不需要同步等待这个链路可用;

Selector线程可以同时处理成千上万个客户端连接,而且性能不会随客户端的增加而线性下降,非常适合高性能、高负载的网络服务器。

AIO编程

AIO是NIO2.0,它引入了异步通道概念,提供了异步文件通道和异步套接字通道的实现。异步通道提供了java.util.concurrent.Future类来表示异步操作的结果。

在执行异步操作时候传入一个java.io.channels.

CompletionHandler接口的实现类作为操作完成的回调。

NIO2.0的异步套接字通道是真正的异步非阻塞I/O,它不需要通过多路复用器Selector对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO的编程模型。

现在看看逐个看看相关模型和代码:

BIO模型

传统的BIO代码 时间服务端

  1. package com.example.biodemo;
  2.  
  3. import java.io.*;
  4. import java.net.ServerSocket;
  5. import java.net.Socket;
  6.  
  7. public class TimeServer {
  8. public static void main(String[] args) throws IOException {
  9. int port = 8090;
  10. if (args != null && args.length > 0) {
  11. try {
  12. port = Integer.valueOf(args[0]);
  13. } catch (NumberFormatException e) {
  14. port = 8090;
  15. }
  16. }
  17. ServerSocket server = null;
  18. try {
  19. server = new ServerSocket(port);
  20. System.out.println("the timeServer is start in port :" + port);
  21. Socket socket = null;
  22. while (true) {
  23. socket = server.accept();
  24. new Thread(new TimeServerHandler(socket)).start();
  25. }
  26. } finally {
  27. if (server != null) {
  28. System.out.println("the time server close");
  29. server.close();
  30. server = null;
  31. }
  32. }
  33.  
  34. }
  35. }

传统BIO 时间处理

  1. package com.example.biodemo;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.io.PrintWriter;
  7. import java.net.Socket;
  8.  
  9. public class TimeServerHandler implements Runnable {
  10. private Socket socket;
  11.  
  12. public TimeServerHandler(Socket socket) {
  13. this.socket = socket;
  14. }
  15.  
  16. @Override
  17. public void run() {
  18. BufferedReader in = null;
  19. PrintWriter out = null;
  20. try {
  21. in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  22. out = new PrintWriter(this.socket.getOutputStream(), true);
  23. String currentTime = null;
  24. String body = null;
  25. while (true) {
  26. body = in.readLine();
  27. if (body == null) {
  28. break;
  29. }
  30. System.out.println("the time server receive order:" + body);
  31. currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString() : "bad order";
  32. out.println(currentTime);
  33.  
  34. }
  35. } catch (Exception e) {
  36. if (in != null) {
  37. try {
  38. in.close();
  39. } catch (IOException el) {
  40. el.printStackTrace();
  41. }
  42. }
  43. if (out != null) {
  44. out.close();
  45. out = null;
  46. }
  47. if (this.socket != null) {
  48. try {
  49. this.socket.close();
  50. } catch (IOException e1) {
  51. e1.printStackTrace();
  52. }
  53. this.socket = null;
  54. }
  55. }
  56. }
  57. }

  客户端代码

  1. package com.example.biodemo;
  2.  
  3. import java.io.*;
  4. import java.net.Socket;
  5.  
  6. public class TimeClient {
  7. public static void main(String[] args) {
  8. int port = 8090;
  9. if (args != null && args.length > 0) {
  10. try {
  11. port = Integer.valueOf(args[0]);
  12. } catch (NumberFormatException ne) {
  13. port = 8090;
  14. }
  15. }
  16. Socket socket = null;
  17. BufferedReader in = null;
  18. PrintWriter out = null;
  19. try {
  20. socket = new Socket("127.0.0.1", port);
  21. System.out.println(socket.getInputStream());
  22. in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  23. out = new PrintWriter(socket.getOutputStream(), true);
  24. out.println("QUERY TIME ORDER");
  25. System.out.println("send order 2 server succeed.");
  26. String resp = in.readLine();
  27. System.out.println("now is :" + resp);
  28. } catch (IOException e1) {
  29.  
  30. } finally {
  31. if (out != null) {
  32. out.close();
  33. out = null;
  34. }
  35.  
  36. if (in != null) {
  37. try {
  38. in.close();
  39. } catch (IOException e2) {
  40. e2.printStackTrace();
  41. }
  42. in = null;
  43. if (socket != null) {
  44. try {
  45. socket.close();
  46. } catch (IOException e3) {
  47. e3.printStackTrace();
  48. }
  49.  
  50. }
  51. socket = null;
  52. }
  53.  
  54. }
  55. }
  56. }

启动服务端

启动客户端

再看看服务端

整个过程是:服务端先在某一端口启动服务,本博主是在8090上启动,启动后,客户端启动,发送请求,请求被服务端接收后,进行逻辑处理,并将逻辑处理结果返回,这里的逻辑处理结果是当前时间,返回的结果客户端接收后显示出来。这就是一个典型的BIO模型。

netty权威指南学习笔记一——NIO入门(1)BIO的更多相关文章

  1. netty权威指南学习笔记一——NIO入门(3)NIO

    经过前面的铺垫,在这一节我们进入NIO编程,NIO弥补了原来同步阻塞IO的不足,他提供了高速的.面向块的I/O,NIO中加入的Buffer缓冲区,体现了与原I/O的一个重要区别.在面向流的I/O中,可 ...

  2. netty权威指南学习笔记一——NIO入门(4)AIO

    NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现.异步通道提供以下两种方式获取操作结果. 1.通过java.util.concurrent.Future 类来表示异步操 ...

  3. netty权威指南学习笔记一——NIO入门(2)伪异步IO

    在上一节我们介绍了四种IO相关编程的各个特点,并通过代码进行复习了传统的网络编程代码,伪异步主要是引用了线程池,对BIO中服务端进行了相应的改造优化,线程池的引入,使得我们在应对大量客户端请求的时候不 ...

  4. netty权威指南学习笔记二——netty入门应用

    经过了前面的NIO基础知识准备,我们已经对NIO有了较大了解,现在就进入netty的实际应用中来看看吧.重点体会整个过程. 按照权威指南写程序的过程中,发现一些问题:当我们在定义handler继承Ch ...

  5. netty权威指南学习笔记六——编解码技术之MessagePack

    编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...

  6. netty权威指南学习笔记八——编解码技术之JBoss Marshalling

    JBoss Marshalling 是一个java序列化包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调参数和附加特性,这些参数 ...

  7. netty权威指南学习笔记五——分隔符和定长解码器的应用

    TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,通常采用以下4中方式: 消息长度固定,累计读取到长度综合为定长LEN的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一 ...

  8. netty权威指南学习笔记三——TCP粘包/拆包之粘包现象

    TCP是个流协议,流没有一定界限.TCP底层不了解业务,他会根据TCP缓冲区的实际情况进行包划分,在业务上,一个业务完整的包,可能会被TCP底层拆分为多个包进行发送,也可能多个小包组合成一个大的数据包 ...

  9. netty权威指南学习笔记七——编解码技术之GoogleProtobuf

    首先我们来看一下protobuf的优点: 谷歌长期使用成熟度高: 跨语言支持多种语言如:C++,java,Python: 编码后消息更小,更利于存储传输: 编解码性能高: 支持不同协议版本的兼容性: ...

随机推荐

  1. ORACLE 判断首字母大小写问题

    1.对判断的字段进行拆分 select  substr(要区分的字段,0,1)  from 表 : 得到一个 首字母 2.对这个字符进行大小写判断 查出以小写字符为开头的 select  substr ...

  2. Color Space 和 Color Range

    颜色有两个属性Color Range和Color Space 有关Color Space的解释可以看下面两个链接: https://www.jianshu.com/p/facdbab5ac20 htt ...

  3. Django学习 之后端视图与ajax

    一.Ajax简介 在此之前你一定需要先学习下JavaScript JSON 可见: 前端学习 之 JavaScript 之 JSON 1.简单介绍 我们以前知道的前端向后端发送数据的方式有: GET: ...

  4. mysql 优化策略(如何利用好索引)

    博客园 首页 联系 管理 随笔- 3282  文章- 0  评论- 157  mysql联合索引 命名规则:表名_字段名1.需要加索引的字段,要在where条件中2.数据量少的字段不需要加索引3.如果 ...

  5. Python可视化界面编程入门

    Python可视化界面编程入门具体实现代码如所示: (1)普通可视化界面编程代码入门: import sysfrom PyQt5.QtWidgets import QWidget,QApplicati ...

  6. 十八 Spring的JDBC模板:引入外部属性文件

    配置外部属性文件 配置文件里引入属性文件,两种方式 第一种: 第二种: 引入属性文件的值: 测试: <?xml version="1.0" encoding="UT ...

  7. CSS盒模型的组成部分及实际大小

    盒模型的组成? 盒模型由内容区域.内边距.边框.外边距四部分组成. 盒模型实际大小? 盒模型实际大小由内容区域.内边距.边框三部分组成. 盒模型的box-sizing属性? 如果对盒子不进行设置(或者 ...

  8. Pycharm设置默认HTML模板

    Pycharm设置默认HTML模板 Bootstrap导入链接 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/ ...

  9. java读取ini文件

    ini工具类; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import j ...

  10. RabbitMq学习笔记——概念

    1.RabbitMQ简介 MQ全称为Message Queue(消息队列),是一种“应用程序”<—>“应用程序”的通信方法.MQ是一个典型的“消费”<—>“生产者”模型的代表, ...