一、简介

1. 课程背景

分布式系统的根基在于网络编程,而 Netty 是 Java 领域网络编程的王者。

2. 课程内容

  • 第一部分 NIO 编程,三大组件

  • 第二部分 Netty 入门学习,EventLoop、Channel、Future、Pipeline、Handler、ByteBuf

  • 第三部分 Netty 进阶学习,粘包半包的解决方法、协议的设计、序列化知识

  • 第四部分 Netty 常见参数的学习及优化

  • 第五部分 源码

二、NIO 基础

non Blocking IO 非阻塞 IO

1. 三大组件

1.1 Channel & Buffer

channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是写入,要么是输出。

常见的 Channel 有:

  • FileChannel

  • DatagramChannel

  • SocketChannel

  • ServerSocketChannel

buffer 则用来缓冲读写数据,常见的 buffer 有:

  • ByteBuffer

    • MappedByteBuffer

    • DirectByteBuffer

    • HeapByteBuffer

  • Short/Int/Long/Float/Double/Char Buffer

1.2  Selector

使用多线程技术

为每个连接分别开辟一个线程,分别去处理对应的 socket 连接

:exclamation: 多线程缺点

  • 内存占用高

  • 线程上下文切换成本高

  • 只适合连接数较少的场景

使用线程池技术

使用线程池,让线程池中的线程去处理连接

这种方式存在以下几个问题:

  • 阻塞模式下,线程仅能处理一个连接

  • 仅适合短连接场景

使用 Selector

selector 的作用就是配合一个线程来管理多个 channel(fileChannel 因为是阻塞式的,所以无法使用 selector),获取这些 channel 上发生的事件,这些 channel  工作在非阻塞模式下,当一个 channel 中没有执行任务时,可以去执行其他 channel 中的任务。适合连接数多,但流量较少的场景。

若事件未就绪,调用 selector 的 select() 方法会阻塞线程,直到 channel 发生了就绪事件。这些事件就绪后,select 方法就会返回这些事件交给 thread 来处理。

2.ByteBuffer

使用案例

有一普通文本文件 data.txt 内容为

1234567890abc

使用 FileChannel 来读取文件内容

@Slf4j
public class TestByteBuffer {public static void main(String[] args) {// FileChannel// 1.输入输出流 2.RandomAccessFiletry {FileChannel fileChannel = new FileInputStream("data.txt").getChannel();// 准备缓冲区ByteBuffer buf = ByteBuffer.allocate(10);// 从 Channel 中读取数据,向 Buffer 写入int len;while ((len = fileChannel.read(buf)) != -1) {log.info("读取到的字节:{}", len);buf.flip(); // 切换至读模式log.debug("输出内容为:{}", new String(buf.array(), 0, len));
//                while (buf.hasRemaining()) { // 是否还剩余数据
//                    byte b = buf.get();
//                    log.debug("输出内容为:{}", (char) b);
//                }// 切换为写模式buf.clear();}} catch (IOException e) {e.printStackTrace();}}
}

2.1 ByteBuffer 使用步骤

  1. 向 buffer 写入数据,e.g. 调用 channel.read(buf)

  2. 调用 flip() 切换至读模式

  3. 向 buffer 读取数据,e.g. 调用 buf.get()

  4. 调用 clear()compact() 切换至写模式

  5. 重复 1~4 步骤

2.2 ByteBuffer 结构

核心属性

字节缓冲区的父类 Buffer 中有几个核心属性,如下:

// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
  • capacity:缓冲区的容量。通过构造函数赋予,一旦设置,无法更改。

  • limit:缓冲区的界限。位于 limit 后的数据不可读写。缓冲的限制不能为负,并且不能大于其容量。

  • position:下一个读写位置的索引(类似 PC)。缓冲区的位置不能为负,并且不能大于 limit。

  • mark:记录当前 position 的值。position 被改变后,可以通过调用 reset() 方法恢复到 mark 的位置。

核心方法:

put() 方法

  • put() 方法可以将一个数据放入缓冲区

  • 进行该操作后,position 的值会 +1,指向下一个可以放入的位置。capacity = limit。

flip() 方法

  • flip() 方法会切换对缓冲区的操作模式,由写 -> 读 / 读 -> 写

  • 进行该操作后

    • 如果是 写模式 -> 读模式,position = 0,limit 指向最后一个元素的下一个位置,capacity 不变

    • 如果是读 -> 写,则恢复为 put() 方法中的值

get()方法

  • get() 方法会读取缓冲区中的一个值

  • 进行该操作后,position 会 +1,如果超过了 limit 则会抛出异常

  • 注意:get(i)方法不会改变 position 的值

rewind() 方法

  • 该方法只能在读写模式下使用

  • rewind() 方法后,会恢复 position、limit 和 capacity 的值,变为进行 get() 前的值

clean() 方法

  • clean() 方法会将缓冲区中的各个属性恢复为最初的状态,position = 0,capacity = limit

  • 此时,缓冲区的数据依然存在,处于“被遗忘”状态,下次进行写操作时会覆盖这些数据

mark()reset()方法

  • mark() 方法会将 position 的值保存到 mark 属性中

  • reset() 方法会将 position 的值改为 mark 中保存的值

compact() 方法

此方法为 ByteBuffer 的方法,而不是 Buffer 的方法

  • compact() 会把未读完的数据向前压缩,然后切换到写模式

  • 数据前移后,原位置的值并未清零,写时会覆盖之前的值

2.2 ByteBuffer 结构

ByteBuffer 有以下重要属性

  • capacity

  • position

  • limit

刚开始

0021

写模式下,position 是写入位置,limit 等于容量,下图表示写入了 4 个字节后的状态。

0018

flip 动作发生后,position 切换为读取位置,limit 切换为读取限制。

读取 4 个 byte 后,状态:

clear 动作发生后,状态变为一开始。

compact() 方法,是把未读完的部分向前压缩,然后切换至写模式。

Netty:Java 领域网络编程的王者相关推荐

  1. 你对Java网络编程了解的如何?Java BIO 网络编程 | Netty 前期知识

    一步一步走来,之前去学习了JUC并发编程知识,现在终于到Java IO网络编程啦,难啊. 一.BIO介绍 引入: 随着技术的发展,两个或以上的程序必然需要进行交互,于是提供了一种端到端的通信,相当于对 ...

  2. JAVA的网络编程【转】

    转自 http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能 ...

  3. 四十六、深入Java的网络编程(下篇)

    @Author:Runsen @Date:2020/6/9 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  4. 四十五、深入Java的网络编程(上篇)

    @Author:Runsen @Date:2020/6/8 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  5. java的网络编程有用吗_十大有用但又偏执的Java编程技术

    java的网络编程有用吗 经过一段时间的编码(以我为例,大约20年左右,当您玩得开心时光飞逝),人们开始接受这些习惯. 因为,你知道... 任何可能出错的事情都会发生. 这就是为什么人们会采用&quo ...

  6. java中no1_【Java】-- 网络编程のNo.1

    在现有的网络中,网络通讯的方式主要有两种: TCP(传输控制协议)方式 UDP(用户数据报协议)方式 在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后 ...

  7. 【零基础学Java】—网络编程(五十三)

    [零基础学Java]-网络编程(五十三) 一.软件结构 C/S结构:全称为Client/Server结构,是指客户端和服务器结构,常见的程序有QQ.迅雷等软件 B/S:全称为Browser/Serve ...

  8. Java面向对象 网络编程 上

     Java面向对象 网络编程 上 知识概要:                     (1)网络模型 (2)网络通讯要素 (3)UDP TCP 概念 (4)Socket (5)UDP TCP 传输 ...

  9. 什么是java socket_java 网络编程,Socket编程

    Java的网络编程主要涉及到的内容是Socket编程,那么什么是Socket呢?简单地说,Socket,套接字,就是两台主机之间逻辑连接的端点.TPC/IP协议是传输层协议,主要解决数据如何在网络中传 ...

最新文章

  1. 利用startup.m文件设置matlab的Current Folder的默认文件夹
  2. php javabean对象,Struts2 bean标签:创建并示例化一个JavaBean对象
  3. C#网络编程(基本概念和操作) - Part.1
  4. 手把手教你用1行代码实现人脸识别 -- Python Face_recognition
  5. 我在SharePoint行业的从业经历(一)
  6. Mac OS X 下Java开发环境配置
  7. 学习OpenVINO笔记之Inference Engine
  8. Ubuntu16.04开机引导缺失Win10
  9. 输入图像四通道 输出图像四通道
  10. u3d+向服务器上传文件,unity3d向服务器传数据库
  11. 机器学习与数据挖掘_线性模型 II
  12. php缓存技术基础知识
  13. VS生成dump文件和调试dump文件
  14. 设计模式星火01_单例模式
  15. 【每周一读】——你的孤独,虽败犹荣
  16. Vue3.0新特性及使用方法
  17. 计算机专业ps社会实践报告模板,社会实践调查报告范文_个人陈述(PS)写作注意_沪江英语...
  18. 《c语言项目》学生成绩管理系统(devc++)
  19. 京东2017实习生招聘试题 构造方法
  20. 小米小贷业务生变,消费贷业务并入小米消金

热门文章

  1. manjaro mysql_如何看待manjaro的软件仓库连个mysql都没有?
  2. 暑期集训3:几何基础 练习题G: HDU - 1052
  3. Vijos1683 有根树的同构问题
  4. VMware workstation中rhel安装VMware tools失败
  5. BZOJ.5249.[九省联考2018]iiidx(贪心 线段树)
  6. Codeforces 894.D Ralph And His Tour in Binary Country
  7. 47种常见的浏览器兼容性问题大汇总
  8. C++构造函数(一)
  9. RequireJS学习笔记(转)
  10. ARM、FPGA和DSP的特点和区别是什么?(转)