Netty权威指南

article/2025/9/14 15:09:42

Chapter1.java I/O演进之路

1.1I/O基础入门

在java 1.4之前,java程序员在开发高性能I/O程序的时候,会面临的问题主要有:

1.没有数据缓冲区,I/O性能存在问题
2.没有c或者c++中的Channel概念,只有输入和输出流
3.同步阻塞式I/O通信(BIO),通常会导致通信线程被长时间阻塞
4.支持的字符集有限,硬件可移植性不好

1.1.1Linux网络I/O模型简介

根据UNIX网络编程对I/O模型的分类,UNIX提供了5种I/O模型:

1.阻塞I/O模型
2.非阻塞I/O模型
3.I/O复用模型
4.信号驱动I/O模型
5.异步I/O

对于大多数java程序员来说,不需要了解网络编程的底层细节,只需要知道,对于操作系统而言,底层是支持异步I/O通信的,只不过在很长一段时间java并没有提供异步I/O通信的类库。

java NIO的核心类库多路复用器Selector就是基于epoll的多路复用技术实现的。

1.1.2I/O多路复用技术

与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降低了系统的维护工作量。

支持I/O多路复用的系统调用select,pselect,poll,epoll,epoll相比于他们,有了很大的改进,主要有:

1.支持一个进程打开的socket描述符(FD)不受限制(仅受限于操作系统的最大文件句柄数)
关于这个最大文件句柄数,可以通过cat /proc/sys/fs/file-max查看。

2.I/O效率不会随着FD数目的增加而线性下降

3.使用mmap加速内核与用户空间的消息传递
无论是select,poll还是epoll都需要内核把FD消息传递给用户空间,如何避免不必要的内存复制就显得非常重要了,epoll是通过内核和用户空间mmap同一块内存实现。

4.epoll的API更简单
包括创建一个epoll描述符,添加监听事件,阻塞等待所监听的事件发生,关闭epoll描述符等。

1.2Java的I/O演进

在JDK1.4推出Java NIO之前,基于Java的所有Socket通信都采用了同步阻塞模式(BIO),这种一请求一应答的通信模型简化了上层的应用开发,但是在性能和可靠性方面存在着巨大的瓶颈。

Chapter2.NIO入门

2.1传统的BIO编程

网络编程的基本模型是client/server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建立连接,如果连接建立成功,双方就可以通过Socket进行通信。

在基于传统同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作,连接成功后,双方通过输入和输出流进行同步阻塞通信。

2.1.1BIO通信模型图

采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接受到连接请求后,为每一个客户端创建一个新的处理线程进行链路处理,处理完成之后,通过输出流返回给客户端,线程销毁。

该模型最大的问题是,缺乏弹性伸缩能力,当客户端并发访问量增加时,服务端的线程个数和客户端并发访问数呈1:1的关系,系统性能下降。

为了改进一线程一连接的模型,后来又演进出了一种通过线程池或者消息队列实现1个或者多个线程处理N个客户端的模型,由于它的底层通信机制依然使用同步阻塞I/O,所以被称为“伪异步”。

2.2伪异步I/O编程

后端通过一个线程池来处理多个客户端的请求接入,形成客户端个数M:线程池最大线程数N的比例关系,其中M可以远远大于N,通过线程池可以灵活的调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。

2.2.1伪异步I/O模型图

当有新的客户端接入的时候,将客户端的Socket封装成一个Task(该任务实现java.lang.Runnable接口),投递到后端的线程池中进行处理,JDK的线程池维护一个消息队列和N个活跃线程对消息队列中的任务进行处理。由于线程池可以设置消息队列的大小和最大线程数,因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽和宕机。

伪异步I/O通信框架采用了线程池实现,因此避免了为每个请求都创建一个独立线程造成线程资源耗尽问题。但是由于它底层的通信依然采用同步阻塞模型,因此无法从根本上解决问题。

2.2.3伪异步I/O弊端分析

要深入分析,需要看两个Java同步I/O的API说明:

InputStram中read方法
//this method blocks until input datais available,end of file is detected,or an exception is thrown.
public int read(byte[] b)

解释,当堆Socket的输入流进行读取操作的时候,它会一直阻塞下去,知道发生下列三种事件:

1.有数据可读
2.可用数据已经读取完毕
3.发生空指针或者I/O异常

这意味着当对方发送请求或者应答消息比较缓慢,或者网络传输较慢时,读取输入流一方的通信线程将被长时间阻塞。如果对方要60s才能够将数据发送完成,读取一方的I/O线程也将会被同步阻塞60s,在此期间,其他接入信息只能在消息队列中排队。

OutputStram中write方法
//writes an array of bytes.this method will block until the bytes are actually written.
public int write(byte[] b)

当调用OutputStream的write方法写输出流的时候,它将会被阻塞,知道所有要发送的字节全部写入完毕,或者发生异常。

学习过TCP/IP相关知识的都知道,当消息的接收方处理缓慢的时候,将不能及时地从TCP缓冲区读取数据,这将导致发送方的TCP window size不断减小,直到为0,双方处于Keep-Alive状态,消息发送方将不能再向TCP缓冲区写入消息,这时如果采用的是同步阻塞I/O,write操作将会被无限期阻塞,知道TCP window size大于0或者发生I/O异常。

通过对输入和输出流的API文档进行分析,我们了解到读和写操作都是同步阻塞的,阻塞的时间取决于对方I/O线程的处理速度和网络I/O的传输速度。但是,我们无法保证在生产环境中这些都是可控的,这是同步方式的致命弱点。

下面简单分析如果通信对方返回应答时间过长,会引起的级联故障:

1.服务端处理缓慢,返回应答消息耗费60s,平时只需要10ms。
2.采用伪异步I/O的线程正在读取故障服务节点的响应,由于读取输入流是阻塞的,因此,它将会被同步阻塞60s。
3.假如所有的可用线程都被故障服务器阻塞,那后续所有的I/O消息都将在队列中排队。
4.由于线程池采用阻塞队列实现,当队列堆积满之后,后续入队列的操作将被阻塞。
5.由于前端只有一个Acceptor线程接收客户端接入,它被阻塞在线程池的同步阻塞队列之后,新的客户端请求消息将被拒绝,客户端会发生大量的连接超时。
6.由于几乎所有的连接都超时,调用者会认为系统已经崩溃,无法接受新的请求消息。

2.3NIO编程

一般来说,低负载,低并发的应用程序可以选择同步阻塞I/O以降低编程复杂度,但是对于高负载,高并发的网络应用,需要使用NIO的非阻塞模型进行开发。

2.3.1NIO类库简介

1.缓冲区Buffer

Buffer是一个对象,它包含一些要写入或者要读出的数据。
不同:在面向流的I/O中,可以将数据直接写入或者将数据直接读到Stream对象中。在NIO中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,写入到缓冲区中。
任何时候访问NIO中的数据,都是通过缓冲区进行操作

除了ByteBuffer,每一个Buffer内都有完全一样的操作,只是它们所处理的数据类型不一样。

2.通道Channel

Channel是一个通道,可以通过它读取和写入数据,网络数据通过Channel读取和写入。通道和流的不同之处在于通道是双向的,流只是在一个方向上移动(一个流必须是InputStream或者OutputStream的子类),而且通道可以用于读,写或者同时用于读写。

因为Channel是全双工的,所以它可以比流更好地映射底层操作系统的API。特别是在UNIX网络编程模型中,底层操作系统的通道都是全双工的,同时支持读写操作。

实际上Channel可以分为两大类:分别是用于网络读写的SelectableChannel和用于文件操作的FileChannel

3.多路复用器Selector

它是Java NIO编程的基础。多路复用器提供选择已经就绪的任务的能力

简单来讲,Selector会不断地轮询注册在其上的Channel,如果某个Channel上面有新的TCP连接接入,读和写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。

一个多路复用器Selector可以同时轮询多个Channel,由于JDK使用了epoll()代替传统的select实现,所以它并没有最大连接句柄1024/2048的限制。这也就意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端,确实是非常大的进步。

NIO编程难度比同步阻塞BIO大很多,这些难度还不包括“半包读”和“半包写”,如果考虑这些,难度更大。但是NIO的优点足以让其值回票价:

1.客户端发起的连接操作是异步的,可以通过在多路复用器注册OP_CONNECT等待后续结果,不需要像之前的客户端那样被同步阻塞。
2.SocketChannel的读写操作都是异步的,如果没有可读写数据它不会同步等待,直接返回,这样I/O通信线程就可以处理其他的链路,不需要同步等待这个链路可用。
3.线程模型的优化:通过epoll实现,没有连接句柄数的限制

JDK7升级了NIO类库,被称为NIO2.0,值得注意的是,Java正式提供了1.异步文件I/O操作,同时提供了2.与UNIX网络编程事件驱动I/O对应的AIO

2.4AIO编程

2.5 4种I/O对比

这里写图片描述

2.6.1不选择Java原生NIO编程的原因

1.NIO的类库和API繁杂,使用麻烦,你需要熟练使用Selector,ServerSocketChannel,SocketChannel,ByteBuffer等。
2.需要具备其他的额外技能做铺垫,例如熟悉Java多线程编程。
3.可靠性能力补齐,工作量和难度都非常大。
4.Java NIO的BUG。

Chapter3.Netty入门应用

Chapter4.TCP粘包/拆包问题的解决之道

4.1TCP粘包/拆包

TCP是个“流”协议,所谓流,就是没有界限的一串数据。所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小包封装成一个大的数据包进行发送。

4.1.3粘包问题的解决策略

由于底层的TCP无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决(比如HTTP协议),根据业界的主流协议的解决方案,可以归纳如下:

1.消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格。
2.在包尾添加回车换行符进行分割,例如FTP协议。
3.将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常涉及思路为消息头的第一个字段使用int32 来表示消息的总长度。
4.更复杂的应用层协议

4.3.4LineBasedFrameDecoder和StringDecoder的原理分析

LineBasedFrameDecoder的工作原理是它依次遍历ByteBuf中的可读字节,判断看是否有”\n”或者”\r\n”,如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。

StringDecoder的功能非常简单,就是将接收到的对象转换成字符串,然后继续调用后面的handler。LineBasedFrameDecoder+StringDecoder组合就是按行切换的文本解码器,它被设计用来支持TCP的粘包和拆包。

当然,Netty中还提供了很多其他的解决TCP粘包和拆包的解码器,满足不同的需求!

5.3总结

DelimiterBasedFrameDecoder用于对使用分隔符结尾的消息进行自动解码,FixedLengthFrameDecoder用于对固定长度的消息进行自动解码。

Chapter6.编解码技术

Java序列化的目的主要有两个

1.网络传输
2.对象持久化

Java序列化仅仅是Java编解码技术的一种,由于它的种种缺陷,衍生出很多种编解码技术和框架。

6.1Java序列化的缺点

1.无法跨语言
2.序列化后的码流太大
3.序列化性能太低

6.2业界主流的编解码框架

1.Google的Protobuf
2.Facebook的Thrift

Chapter11.WebSocket协议开发

长期以来存在着各种技术让服务器得知有新数据可用时,立即将数据发送到客户端。这些技术种类繁多,例如“推送”或Comet。最常用的是对服务器发起链接创建假象,被称为长轮询。长轮询和其他技术都非常好用,在Gmail聊天等应用中会经常使用它们。

但是,这些解决方案都存在一个共同的问题:由于HTTP协议的开销,导致它们不适用于低延迟应用

为了解决这些问题,WebSocket将网络套接字引入到了客户端和服务端,浏览器和服务器之间可以通过套接字建立持久的连接,双方随时都可以互发数据给对方,而不是之前由客户端控制的一请求一应答模式

11.1HTTP协议的弊端

主要弊端如下:

1.HTTP协议为半双工协议。
2.HTTP消息冗长而繁琐
3.针对服务器推送的黑客攻击,例如长时间轮询。

现在很多网站为了实现消息推送,所用的技术都是轮询。轮询的思想和实现都很简单,但是会占用很多的带宽和服务器资源。

比较新的一种轮询技术是Comet,使用了Ajax。这种技术虽然可达到双向通信,但依然需要发出请求,而且在Comet中,普遍采用了长连接,也会有上述性能问题。

11.2WebSocket入门

WebSocket特点:

1.单一的TCP连接,采用全双工模式通信
2.对代理,防火墙和路由器透明
3.无头部信息,Cookie和身份验证
4.无安全开销
5.通过”ping/pong”帧保持链路激活
6.服务器可以主动传递消息给客户端,不再需要客户端轮询

WebSocket设计出来的目的就是要取代轮询和Comet技术,使客户端浏览器具备像C/S架构下桌面系统一样的实时通信能力。

the end


http://chatgpt.dhexx.cn/article/AisyraRw.shtml

相关文章

三维视觉传感器的类型

三角法测量原理 视觉传感器的坐标系统 单一摄像机二维传感器 点结构光视觉传感器 线结构光视觉传感器 条纹结构光视觉传感器 条纹编码三维视觉传感器 彩色编码视觉传感器 被动双目视觉传感器 编码照明双目视觉传感器

传感器sensor

传感器分类 转换原理 传感器名称 典型应用 转换形式 中间参量 电 参 数 电 阻 移动电位器角点 改变电阻 电位器传感器 位移 改变电阻丝或片尺寸 电阻丝应变传感器、半导体应变传感器 微应变、力、负荷 利用电阻的温度效应 热丝传感器 气流速度、液体流量 电阻…

多任务多传感器数据融合实现3D目标检测

转载自:自动驾驶之心 01 引言 本文介绍一篇uber公司在CVPR上发表的一篇论文,即使用多种传感器(LiDAR和RGB相机)数据,以及多任务进行数据融合,实现准确高效的3D目标检测。简而言之,自动驾驶领域…

压力传感器

压力传感器 压力传感器是最常用的一种传感器,其应用范围有各种工业互通环境,涉及航空,航天,军工,石化,电力等。按照不同的测试,压力类型可分表压传感器,差压传感器,绝压…

多传感器融合定位(一)——3D激光里程计

目录 一、点云地图整体流程 二、激光里程计方案 2.1 ICP点到点 2.1.1 ICP推导 2.1.2 ICP改进 2.2 NDT 2.2.1 NDT推导 2.2.2 NDT改进 2.3 LOAM系 2.3.1 LOAM 2.3.2 A-LOAM 2.3.3 LEGO-LOAM 2.4 数据集及评价指标 2.4.1 KITTI简介 2.4.2 指标 一、点云地图整体流程…

MMDetection3D 1.1:统一易用的 3D 感知平台

自从两年前 MMDetection3D 发布以来,我们收到了很多用户的反馈,其中有不少有价值的建议,同时也有很多吐槽(当然我们非常欢迎大家来吐槽),也有很多社区用户参与到我们代码库的完善中,我们也非常高…

关于传感器

人的眼睛就是传感器。人对光的感应靠眼睛,在光亮条件下,人眼能分辨各种颜色。首先从人眼构造开始讲起。眼睛最里面的膜是视网膜,它布满了整个眼睛后部的内壁。当眼球适当地聚焦时,来自眼睛外部的光在视网膜上成像。在视网膜表面分…

ToF 3D视觉传感技术详解、应用场景和市场前景

‍转载自:3d tof 现行的深度传感镜头作为智能手机的一大创新,已在目前主流智能手机上广泛应用。现因苹果在最新版iPad Pro上搭载了D-ToF(直接飞行时间法)深度传感镜头引起了极大的关注,推动了3D视觉在消费场景的新应用…

奥比中光Orbbec Astra Pro RGBD 3D视觉传感器在ROS(indigo和kinetic)使用说明

作者:童虎 编辑:3D视觉开发者社区 Orbbec Astra Pro传感器在ROS(indigo和kinetic)使用说明 这款摄像头使用uvc输入彩色信息,需要libuvc和libuvc_ros这样才能在ROS正常使用彩色功能。 请在下面网址,分别下载…

3D传感相关

这里涉及了各种3D传感相关的工作,包含单目、双目、ToF等传感器,涉及了计算摄影、ToF深度测量、双目深度估计、多视角深度估计、相机离线标定、相机在线标定、NeRF等技术,可谓3D视觉集大成者。 这里简单介绍下本文将会提到的两种3D成像技术&a…

3D激光雷达SLAM算法学习02——3D激光雷达传感器

1.本篇思维导图 2. 3D激光雷达传感器分类 3. 机械激光雷达 直观视频感受:Velodyne 优点:360视野,精度高,工作稳定,成像快 缺点:成本较高,不符合自动驾驶车规,生命周期短&#xff0c…

Lidar 3D传感器点云数据与2D图像数据的融合标注

2D&3D融合 以自动驾驶场景为例,自动驾驶汽车需要使用传感器来识别车辆周围的物理环境,用来捕获2D视觉数据,同时在车辆顶部安装雷达,用以捕捉精确目标定位的3D位置数据。 激光雷达生成的点云数据可用于测量物体的形状和轮廓,估…

3D视觉传感器产业现状-2018年

总结一下,主要参考于MEMS市场调研 MEMS.ME, 必须找专业的分析和咨询公司才行,或者活跃在前沿的资深行业专家。市场分析只能给出大致的销售状况,还不能给出详细的技术数据对比。 从三维重建的算法、技术原理和效果参数上分析&#…

三种常见的3D传感器比较

作者 | dianyunPCL 编辑 | 点云PCL 本文只做学术分享,如有侵权,联系删文 点击下方卡片,关注“自动驾驶之心”公众号 ADAS巨卷干货,即可获取 点击进入→自动驾驶之心【硬件交流】技术交流群 摘要 在过去的十年里,3D传感…

3D视觉|了解下工业上常见的3D相机

说起相机,大家估计都很熟悉了。那么相对于平常使用的2D相机,3D相机又有哪些区别呢,顾名思义,3D相机可以让我们获取我们物理世界的空间信息,即立体三维的物理信息。多了一个维度的信息,似乎打开了一扇大门&a…

基于多传感器的3D多目标跟踪算法汇总

1. IROS 2020-AB3DMOT:A Baseline for 3D Multi-Object Tracking and New Evaluation Metrics 代码链接:https://github.com/xinshuoweng/AB3DMOT 文章链接:http://www.xinshuoweng.com/papers/AB3DMOT_eccvw/camera_ready.pdf 出发点&#x…

3D相机技术 | 立体视觉传感器+TOF相机

转自 | 睿慕课 文章结构 前言立体视觉传感器原理简介工业领域应用主流立体视觉的产品TOF相机工作原理TOF工业领域应用一些TOF研究机构 1.前言 在机器视觉应用中,物体三维形状的获取变得越来越重要。在这个系列里,我们将讨论目前在机器视觉行业中可用的3…

一文聊聊用于机器感知的3D与2D传感器数据 | 数据标注

人类和机器之间最大的区别之一在于我们感知周围环境的方式。我们都存在于3D世界中,人类天生能够感知复杂的几何形状、透视、遮挡、消失点、物体持久性等带来的影响,但机器却很难处理这些最简单的情况。 想让他们能够“看到”仍然是一个热门的研究领域。机…

多传感器融合 | CenterFusion:毫米波雷达和相机后融合3D检测算法

点击下方卡片,关注“自动驾驶之心”公众号 ADAS巨卷干货,即可获取 今天自动驾驶之心很荣幸邀请到寒风分享RV后融合算法CenterFusion,如果您有相关工作需要分享,请在文末联系我们! >>点击进入→自动驾驶之心【多传…

Ansys Lumerical Zemax Speos | CMOS 传感器相机:3D 场景中的图像质量分析

在本例中,我们介绍了一个仿真工作流程,用于在具有不同照明条件的特定环境中,从光学系统和CMOS成像器的组合中分析相机系统的图像质量。此示例主要涵盖整个工作流程中的Ansys Speos部分。该光学系统采用Ansys Zemax OpticStudio设计&#xff0…