1.tomcat和netty对比
1.1 tomcat介绍
tomcat是web应用服务器,由一系列组件构成,核心组件由以下三个:
web容器(完成web服务器的功能)
servlet容器(名字为catalina,用于处理servlet代码)
jsp容器(用于将jsp动态网页翻译成servlet代码)
因此,tomcat是应用服务器,也是servlet/jsp容器,作为servlet容器,tomcat负责处理客户请求,将请求传给servlet,并将servlet的响应传回客户。
在中小型系统和并发访问用户不是很多的场合下,tomcat被普遍使用,是开发和调试jsp的首选。
1.2 tomcat支持的协议
HTTP/1.1:体现在持久连接、请求和响应的处理、虚拟机主持、请求的路由和处理、错误处理和日志记录以及兼容性和向后兼容性等方面。是的tomcat作为一款可靠的web服务器,为使用
HTTP/1.1协议提供了良好支持
HTTP/2.0:tomcat从8.5版本开始支持HTTP/2.0协议。该协议在传输方面进行了重要改进,包括采用二进制传输而非HTTP/1.1协议的文本格式,支持服务推送等。
主要通过移除SPDY/2的相关功能实现,因为HTTP/2.0虽然和SPDY有所不同,但两者之间存在相似之处。
HTTP/2.0协议中,一个基本的协议单元是帧,与TCP中的数据包概念相似。
AJP:tomcat中,AJP协议主要用于连接apache http服务器和其他反向代理服务器,实现web服务器和servlet容器之间的通信。
通过AJP连接器,tomcat可以与支持AJP协议的web服务器进行集成,提供更好的性能和扩展性。
1.3 tomcat优缺点
优点:轻量级和易部署、开源、稳定性好、支持servlet和jsp、支持多种应用(不仅可以作为web服务器运行,还可作为独立的应用服务器运行,支持多种应用和框架)
缺点:内存占用较大(可能会影响性能)、线程数量限制(可能影响并发的性能)、
安全性(tomcat虽采取了安全配置,但用户仍需额外的安全措施来保护自己的应用程序和数据)、需用户自行负责更新和维护
1.4 netty介绍
netty是java开源框架,提供异步的、事件驱动的网络应用程序框架和工具,用来快速开发高性能、高可靠性的网络服务器和客户端程序。
是基于NIO的客户端、服务器端的编程框架,
使用netty可确保快速和简单开发一个网络应用,例如实现了某种协议的客户端、服务端应用。Netty相当简化和流水线化了网络应用的编程开发过程。
例如,基于TCP和UDP的socket服务开发,快速和简单并不用产生维护性或性能上的问题。
Netty是一个吸收了多种协议的实现经验,并经过精心设计的项目。Netty在保证易于开发的同时还保证了应用的性能,稳定性和伸缩性。
此外,netty整合了网络编程、多线程处理和并发多个领域,极大地简化了网络开发的流程。
netty本质上是一个NIO框架,适用于服务器通讯相关的多种应用场景。可快速和轻松的开发网络应用程序,如协议服务器和客户端。极大地简化了TCP和UDP套接字服务器等网络编程。
1.5 netty支持的协议,包括但不限于
tcp/udp:提供了基于nio的tcp和udp编程框架,可用来构建高性能、高可用的网络应用
http/https:提供了http/https编程框架,可用来开发web服务器和客户端
websocket:提供了websocket编程框架,可用来开发双向通信应用程序,如聊天室等
spdy/http2:提供了spdy/http2编程框架,可用来实现高效的web应用
mqtt/coap:提供了mqtt/coap编程框架,可用来开发iot应用
此外,还支持各种二进制和文本协议,如ftp、smtp等。这些协议都是通过netty的channelhandler来处理的,只需要根据业务需求实现对应的channelhandler即可。
1.6 netty优点:使用简单,开发门槛低、功能强大、定制能力强、性能高、成熟稳定
1.7 netty和tomcat的区别:
作用:tomcat是servlet容器,可被视为web服务器;netty是异步事件驱动的网络应用程序框架和工具,用户简化网络编程。例如tcp和udp套接字服务器
协议:tomcat基于http协议的web服务器,netty可通过编程自定义各种协议,因为netty本身可编码和解码字节流,所以netty可实现http服务器、ftp服务器、udp服务器、
rpc服务器、websocket服务器、redis的proxy服务器、mysql的proxy服务器等
性能:虽然某些方面tomcat有较好的,但是netty的性能更好。
选择tomcat还是netty,主要取决于具体需求。构建高性能、高并发的网络应用,并且需要实现自定义协议,则netty更为合适。因为netty的异步、事件驱动的设计模式更好地应对高并发场景,并且支持自定义协议,提供了更为灵活的网络编程框架。如果是构建web应用服务器,并且基于http协议的应用较多,则tomcat更为合适。因为tomcat一度是web容器的标准,并且对http层的支持更完善。
1.8 netty和tomcat的应用场景:
tomcat主要用于传统的web应用程序,如电子博客、商务网站等。是一个开源的web服务器,提供了一个容器来运行java应用程序,并处理http请求和响应。tomcat设计目标是提供一种简单、易用、可靠的方式来开发和部署java web应用程序
netty则更适用于处理大量并发连接和高吞吐量的场景,如实时通信、游戏服务器等。netty是一个基于事件驱动的异步网络应用框架,提供了高性能、可扩展的并发能力。设计目标是提供简单、高效、可靠的方式来开发可维护的高性能服务器和客户端。
相同的服务器配置下, netty的并发支持能力通常更高。
tomcat的默认并发数是150,可通过配置提高,但受制于线程数。netty基于NIO,可处理更多的并发连接,并且不需要为每个请求创建新的线程。因此netty在处理大量并发连接时具有更好的性能和效率
1.9 tomcat和netty来处理大量并发连接的优化
netty优化方式:
异步和事件驱动的设计:netty通过异步和事件驱动的设计模式,通过非阻塞IO(NIO)连接,可高效地大量处理并发连接,从而无需为每个连接创建新的线程
连接管理和复用:使用连接池和连接复用技术来管理连接,重用已建立的连接,避免频繁创建和销毁连接的开销
流量控制和背压机制:可根据服务器的负载情况动态调整接收和发送数据的速率,避免服务器过载
高效的线程模型:采用多线程模型,通过合理的线程划分和调度,充分利用多核处理器的性能,提高并发处理能力
自定义协议和编码解码器:netty支持自定义协议,并提供丰富的编解码器,可灵活地处理各种协议和数据格式,以满足不同的场景需求
高性能的数据传输:使用了零拷贝技术和缓冲区优化,减少了数据传输过程中的内存拷贝和分配开销,提高了数据传输的效率
监控和调优:netty提供了丰富的监控和调优手段,可以实时检测服务器的性能指标,并根据需要进行调整和优化,以保证系统的稳定性和性能。
总结:通过异步和事件驱动的设计、流量管理和复用、流量控制、高效的线程模型、自定义协议和编解码器、高性能的数据传输、监控和调优,netty能够有效地处理大规模并发连接,并提供高性能、可扩展的网络应用服务。
tomcat优化方式:
服务器配置优化:优化服务器配置,如调整线程池大小、连接器配置等,可提高并发处理能力,可根据实际应用的需求和硬件资源来合理配置
使用负载均衡和集群技术:通过负载均衡将请求分发至多个tomcat实例,可实现水平扩展,提高并发处理能力。同时,集群技术可将多个tomcat实例组成一个集群,共同处理请求,进一步提高并发处理能力。
连接池和连接复用:tomcat也可使用连接池和连接复用技术来管理连接,避免频繁创建和销毁连接的开销
异步处理和事件驱动:虽然tomcat是同步的,但可以通过异步处理和事件驱动的模式来提高并发处理能力。例如使用异步servlet或spring的异步web框架等技术
数据库读写分离:对于数据库的读写操作,可采用读写分离的策略,将读操作和写操作分发到不同的数据库实例,减轻单点数据库的压力,提高并发处理能力。
缓存技术:合理使用缓存,例如redis、memcached等,可减少对数据库的访问次数,减轻数据库的压力,从而提高并发处理能力
监控和调优:通过监控tomcat的性能指标,及时发现瓶颈并调优,如调整JVM参数、优化SQL语句等
总结:通过服务器配置优化、负载均衡和集群技术、连接池的连接复用、异步处理和事件驱动、数据库读写分离、缓存和监控调优等手段,tomcat也可以有效地支持大规模并发连接
1.10 tomcat和netty网络模型的区别
tomcat的网络模型主要有三种:JIO(即BIO)、NIO、NIO2(即AIO)
JIO(Java I/O):传统的同步阻塞模型,即BIO,此模型中,IO操作是同步的,并且当数据未准备好时,线程会被阻塞。适用于连接数较少且数据量大的场景
NIO(Non Blocking I/O):java7引入的模型,支持非阻塞的IO操作,此模型中,IO操作是异步的,当数据未准备好时,线程不会被阻塞,而是可继续执行其他任务,适用于高并发、高吞吐量的场景
NIO2(Asynchronous I/O):JAVA7引入的另一种异步模型,也被称为AIO,与NIO相比,NIO2更简单、更轻量级,提供了基于回调的异步I/O操作。适用需要处理大量并发连接的场景
总结:tomcat7之前,主要适用JIO模型;从tomcat7开始,支持NIO和NIO2模型;tomcat8之后,默认适用NIO模型,可根据需求选择合适的网络模型。
netty的网络模型是基于非阻塞IO(NIO)的,适用了事件驱动和异步的设计模式。netty的核心组件包括channel、eventloop、channelhandler等,通过这些组件的协作,实现高效的网络通信
netty网络模型特点:
事件驱动:netty的事件驱动设计使它能够高效地处理并发连接,当网络事件发生时,netty会将其封装成一个事件对象,并传递给相应的channelhandler进行处理
异步性:netty的异步性使它不会阻塞线程等待IO操作完成,而是通过回调函数通知处理完成或错误消息,这种异步的设计使netty更够处理更多的并发连接
内存池化:netty使用了内存池化技术,通过预先分配一定数量的bytebuf对象,避免频繁的内存和回收操作,减少了GC的次数和提供了性能。
零拷贝:减少了数据在内存中的拷贝次数,提高了数据传输的效率,通过优化文件通道的读写操作,netty能够避免不必要的内存拷贝和数据复制
高度可定制:提供了丰富的channelhandler接口,用户可根据需求实现自定义的channelhandler来处理网络事件,这种可定制性,使netty可适应不同的应用场景
异步事件驱动模型:netty使用异步事件驱动模型来处理网络事件,eventloop会循环监听事件, 当事件到来时,会调用channelhandler进行处理。这种模型使得netty能够充分利用多核cpu的资源,提高处理性能
线程模型:netty使用了多reactor模型,包括一个mainreactor和多个subreactor,mainreactor负责接收新连接,subreactor负责处理已接受的新连接。这种线程模型使得netty能够高效地处理大量并发连接。
1.11 tomcat和netty架构设计:
tomcat架构设计分成以下几个组成部分:
连接器:负责处理http请求和响应的数据流,可以支持多种协议和传输方式,如HTTP、HTTPS、AJP等,连接器可配置多个,每个监听器监听不同的端口
Web容器:负责管理web应用程序,每个应用程序都有一个context,包含了该应用程序的servler、filter、listener等组件的定义和配置.web容器还负责类加载、session管理、安全性等方面的处理。
集群负载均衡(clustering and load balancing):tomcat支持将多个tomcat实例组成一个集群,以提高性能和可用性。集群中的tomcat实例可以通过共享session等方式进行通信,并且可通过负载均衡将请求分发到不同的tomcat实例商。
日志和监控:tomcat提供了丰富的日志记录和监控记录,监控tomcat的监控指标和运行指标
总结:tomcat的架构设计包括连接器、web容器、集群和负载均衡、日志和监控等部分,组件协同工作,使得tomcat能够提供高性能、可扩展的web应用服务
netty架构设计:
netty的架构设计包含以下几部分:
通信调度层:由一系列辅助类完成,包括reactor线程(nioeventloop及其父类)niosocketchannel/nioserversocketchannel及其父类、buffer组件、unsafe组件等。主要职责是负责监听网络层的读写和连接操作,负责将网络层的数据读取到缓冲区,然后触发各种网络事件,例如创建连接、连接激活、读事件、写事件等
责任链层:负责上述的各种网络事件在责任链中的有序传播,同时负责动态地编排责任链。责任链可选择监听和处理自己关心的事件,可以拦截处理事件,以及向前向后传播事件。
总结;netty的设计基于NIO模型,具有异步、事件驱动的特点,可高效地处理大量并发连接。
2.netty入门
2.1 netty说明
是一个NIO客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器端和客户端的协议。
具体来说,netty就是对java nio的封装。nio是java1.4后引入的基于事件模型的非阻塞IO框架。
在NIO之前,对于数据的处理都是基于BIO,BIO是以阻塞的形式对数据进行处理的,虽然处理比较简单,但是由于其阻塞操作会涉及到线程的上下文切换操作,导致BIO在并发场景下略显吃力。
相对,NIO可以较好的应对并发场景。但是NIO推出的NIO类库和API繁杂,使用起来比较麻烦和出现BUG,因此出现了一些列解决NIO问题的框架,Netty就是其中著名的一个.
netty特点:
基于事件机制达成关注点分离(消息编解码,协议编解码,业务处理)
可定制的线程处理模型,单线程,多线程池等
屏蔽NIO本身的BUG
性能上的优化
相较于NIO接口功能更丰富
对外提供统一的接口,底层支持NIO和BIO两种方式,可自由切换
2.2 netty总体架构
总体来说,netty分成两大块:核心模块和服务模块
核心模块:主要提供netty的一些基础基类和底层接口,由三部分组成
zero-copy-capable rich byte buffer(零拷贝缓冲区):用来提升性能,减少资源占用
universal communication api(统一通信api):为同步和异步提供统一的编程接口
extensible event model(易扩展的事件模型)
服务模块:因为netty的核心是io,因此服务模块和IO操作息息相关,主要有:
网络接口数据处理相关服务,如报文的粘包,拆包处理,数据的加密,解密等
各网络层协议实现服务:包括传输层和应用层相关网络协议的实现
文件处理相关服务
2.3 netty处理结构,三层
底层的IO复用层(reactor):负责实现多路复用
中间层的通用数据处理层(pipeline):主要作用是对传输层的数据在进出口进行拦截并处理,比如粘包处理,编解码处理等
顶层的应用实现层:开发者使用netty都是在这一层进行操作,同时netty本身已在这一层提供一些常用的实现,如HTTP协议,FTP协议等
整体流程:数据从网络传输到IO复用层,IO服务层接收到数据后将数据传输至数据处理层进行处理,这一层会通过一系列的handler以及应用服务器对数据进行处理,
然后返回给IO复用层,最后通过它返回给网络
2.4 netty线程模型说明
不同的线程模型对程序的性能有很大的影响,目前存在的线程模型有传统阻塞I/O服务模型Reactor模式
根据Reactor的数量和处理资源池线程的数量又分为三种典型实现,分别是单Reactor线程,单Reactor多线程,主从Reactor多线程.
netty主要基于主从Reactor多线程模型做一定的改进,其中主从Reactor多线程模型有多个Reactor
运行流程:
首先Reactor主线程MainReactor对象通过select监听连接事件,收到事件后,通过Acceptor处理连接事件
Acceptor处理连接事件后,MainReactor将连接分配给SubReactor,然后SubReactor将连接加入到连接队列进行监听,并创建handler进行各种事件处理
当有新的事件发生时,SubReactor就会调用对应的handler来处理.handler通过read来读取数据,分发给后面的worker线程处理
worker线程池分配独立的worker线程进行业务处理,并返回结果
hander收到响应结果后,再通过send将结果返回给client
优点:父线程与子线程数据交互简单,职责明确,父线程只负责接收新连接,子线程完成后续的业务处理
工作原理:
netty抽象了两组线程池bossgroup和workergroup,其中bossgroup专门负责客户端的连接,workergroup专门负责网络的读写.
bossgroup和workergroup的类型都是nioeventloopgroup.nioeventloopgroup相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环是一个nioeventloop
nioeventloop表示一个不断执行处理任务的线程,也就是说可以含有多个nioeventloop,每个nioeventloop都有一个selector,用于监听绑定在其上的socket的网络通讯
每个booseventgroup循环执行的步骤有3步:
轮询accept事件;
处理accept事件,与client建立连接,生成niosocketchannel,并将其注册到某个workernioeventloop上的selector;
处理任务队列的任务,即runalltasks;
每个workernioeventgroup循环执行的步骤也有3步:轮询read,write事件;处理I/O事件,即read,write事件,在对应niosocketchannel处理;处理队列的任务runalltasks
每个workernioeventloop处理业务时,会使用pipeline(管道),pipeline中包含了channel,也就是说通过pipeline可以获取到对应通道,管道中维护了很多的处理器.
3.netty知识点汇总
3.1 NIO基本概念
阻塞(Block)和非阻塞(Non-Block):阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式
阻塞:往往需要等待缓冲区的数据处理好之后才处理其他的事情,否则一直等在哪里
非阻塞:进程访问数据缓冲区的时候,如果数据还未准备好,则直接返回,无需等待.如果数据已准备好,则也直接返回
同步和异步:都是基于应用程序和操作系统处理IO事件所采用的方式.比如:
同步:应用程序直接参与IO读写的操作
同步方式在处理IO事件时,必须阻塞在某个方法上等待IO事件完成(阻塞IO事件或者轮询IO事件的方式)
异步:所有的IO读写交给操作系统去处理,应用程序只需等待通知
此时,可以去做其他的事情,并不需要去完成真正的IO操作,当操作IO完成后,会给应用程序一个通知
异步相对于同步带来的直接好处就是在处理IO数据的时候,异步的方式可以将这部分等待锁消耗的资源用于处理其他事情,提升服务自身的性能.
3.2 BIO和NIO的对比
3.2.1 BIO(传统的IO)
同步并阻塞的IO方式,传统的java.io包,基于流模型实现,提供了一些熟知的IO功能,例如file抽象,输入输出流等.交互方式是同步阻塞的方式,意味着在读取输入流或写入输出流时,在读写
动作完成之前,线程会一直阻塞,它们之间的调用是可靠的线性顺序.
3.2.2 NIO(Non-blocking/New I/O)
NIO是一种同步非阻塞的IO模型,于java1.4引入,对应java.nio包,提供了channel,selector,buffer等抽象.NIO中的N可以理解为Non-blocking,不单纯是new.
支持面向缓冲的,基于通道的IO操作方法
NIO中提供了和传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞方式.
对于高负载,高并发的网络应用,应使用NIO的非阻塞模式来开发
3.3.3 BIO和NIO的对比
BIO:面向流,阻塞IO,无触发
NIO:面向缓冲,非阻塞IO,选择器触发
NIO特点:一个线程可以处理多个通道,减少线程创建数量;读写非阻塞,节约资源;没有可读/可写数据时,不会发生阻塞导致线程资源的浪费
3.3 Reactor模型
3.3.1 单线程的Reactor模型
多个client,多个channel,唯一selector,唯一thread
3.3.2 多线程的Reactor模型
多个client,多个channel,多个selector,多个thread
3.3.3 多线程主从Reactor模型
多个client,多个channel,多个selector,多个thread,多个子channel,子channel对应的多个selector,子channel对应的多个thread
3.4 Netty基本概念
3.4.1 Netty简介
是一个NIO客户端服务器框架,可快速轻松开发网络应用程序,例如协议服务器和客户端,极大地简化了网络编程,例如TCP和UDP套接字服务器
快速简便并不意味着应用程序需遭受可维护性和性能问题的困扰.
netty经过精心设置,结合了许多协议(例如FTP,SMTP,HTTP以及各种基于二进制和文本的旧式协议)的实施经验.
结果,netty成功找到了一种无需妥协即可轻松实现开发,性能,稳定性和灵活性的办法
3.4.2 Netty执行流程
server启动,netty从ParentGroup中选出一个NioEventLoop对指定的port进行监听
client启动,netty从EventLoopGroup中选出一个NioEventLoop对连接server并处理server发送来的数据
client连接server的port,创建channel
netty从childgroup中选出一个nioeventloop与该channel绑定,用于处理该channel的操作
client通过channel向server发送数据包
pineline中的处理器一次对channel中的数据包进行处理
server如需向client发送数据,则需将数据经过pineline中的处理器处理成bytebuffer数据包进行传输
server将数据包通过channel发送给client
pipeline中的处理器一次对channel中的数据包进行处理
3.4.3 Netty核心组件
Channel:是java nio的基本构造,可以看作是传入或传出数据的载体.因此,它可被打开或关闭,连接或断开连接
EventLoop和EventLoopGroup:
EventLoop定义了Netty的抽象,用来处理连接的生命周期中所发生的历史事件,在内部,将会为每个Channel分配一个EventLoop.
EventLoogGroup是一个EventLoop池,包含多个EventLoop
Netty为每个Channel分配了一个EventLoop,用户处理用户连接需求,对用户的请求的处理等所有事件.EventLoop本身只是一个线程驱动,在其生命周期内只会绑定一个线程,让该线程处理一个channel的所有IO事件
一个Channel一旦与一个EventLoop相绑定,那么在channel的整个生命周期内是不能改变的.一个EventLoop可以与多个Channel绑定.即Channel和EventLoop的关系是n:1,
而EventLoop和线程的关系是1:1
ServerBootStrap和BootStrap:BootStrap和ServerBootStrap被称为引导类,指对应用程序进行配置,并使他运行起来的过程.netty处理引导的方式是使应用程序和网络层隔离.
BootStrap是客户端的引导类,BootStrap在调用build(连接UDP)和connect(连接TCP)方法时,会新创建一个Channel,仅创建一个单独的,没有父Channel的Channel来实现所有的网络交换
ServerBootStrap是服务端的引导类,ServerBootStrap在调用build()方法时会创建一个ServerChannel来接受客户端的连接,并且该ServerChannel管理多个子Channel用于客户端之间的通信
ChannelHandler和ChannelPipeline:ChannelHandler是对Channel中数据的处理器,这些处理器可以是系统本身定义好的编解码器,也可以是用户自定义的,这些处理器会被统一添加到一个
ChannelPipeline的对象中,然后按照添加的顺序对Channel中的数据进行依次处理
ChannelFuture:Netty中所有的IO操作都是异步的,即操作不会立即得到返回结果,所以Netty中定义了一个ChannelFuture作为异步操作的代言人,表示异步操作本身.
如果想获得该异步操作的返回值,可以通过该异步对象的addListener()方法为该异步操作添加NIO网络编程框架的Netty监听器,为其注册回调,当结果出来后马上调用执行
Netty的异步编程模型都是建立在Future与回调概念上的.
3.5 Netty源码阅读
最好在debug的情况下进行阅读,因此需要准备客户端和服务端以及对应的handler
3.5.1 server端
EventLoopGroup parentGroup = new NioEventLoopGroup();
EventLoopGroup childGroup = new NioEventLoopGroup();
ServerBootStrap bootstrap = new ServerBootStrap();
bootstrap.group(childGroup,parentGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelIntilizar<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throw Exception{
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder());
pipiline.addLast(new StringEncoder());
pipeline.addLast(new DemoSocketServerHandler());
}
});
ChannelFuture future = bootstrap.bind(8888).sync();
System.out.pringln("服务器已启动");
future.channel().closeFuture().sync();
3.5.2 server端handler
public class DemoSocketServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx,Object msg)throw Exception{
System.out.pringln("Client Address =="+ctx.channel().remoteAddress());
ctx.channel().writeFlush("from server:=="+UUID.randomUUID());
ctx.fierChannelActive();
TimeUnit.MILLISECONDS.sleep(500);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
3.5.3 client端
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
ServerBootStrap bootstrap = new ServerBootStrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.childHandler(new ChannelIntilizar<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throw Exception{
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipiline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new DemoSocketClientHandler());
}
});
ChannelFuture future = bootstrap.connect("localhost",8888).sync();
future.channel().closeFuture().sync();
3.5.4 client端handler
public class DemoSocketClientHandler extends ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx,Object msg) throw Exception{
System.out.println(msg);
ctx.channel().writeAndFlush("from client:"+System.currentTimeMillis());
TimeUnit.MILLISECONDS.sleep(500);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throw Exception{
ctx.channel().writeAndFlush("from client: begin talking");
}
@Override
public void exceptionCaught(ChannelHandlerContext xtx,Throwable cause) throw Exception{
cause.printStackTrace();
ctx.close();
}
}
3.5.5 NioEventLoopGroup初始化分析
先了解下NioEventLoop和NioEventLoopGroup的关系,方便后续源码的理解
NioEventLoop本身是一个单线程的Executor,必然拥有一个execute(Runnable commond)的实现方法,而NioEventLoop的execute()实现方法是在其父类SingleThreadEventExecutor中,
在SingleThreadEventExecutor的execute方法中,有一句startThread();代码,这句代码最终调用了NioEventLoop的一个成员Executor执行了当前成员的execute方法。
对应的成员是:io.netty.util.concurrent.SingleThreadEventExecutor#executor。而executor成员的初始化也是在当前代码执行时创建的匿名Executor,
也就是执行到即新建并且执行当前匿名execute方法
总结:NioEventLoop本身是一个Executor;NioEventLoop内部封装这一个新的线程Executor成员;NioEventLoop有两个execute方法,除了本身的execute方法,还有对应的
成员属性Executor对应的execte方法
NioEventLoopGroup也是一个Executor,并且是一个线程池的Executor,所以也有execute()方法,对应的实现在其父类 io.netty.util.concurrent.AbstractEventExecutorGroup#execute
在NioEventLoopGooup构造中,在其父类MultithreadEventExecutorGroup的构造中再次引入了一个新的Executor,
这个Executor对应的execute()就是在NioEventLoop中的成员Executor的execute()执行时调用的。
总结: NioEventLoopGroup是一个线程池线程Executor;NioEventLoopGroup也封装了一个线程Executor.NioEventLoopGroup也有两个Executor()方法
NioEventLoopGroup初始化代码分析:
NioEventLoopGroup构造方法基本初始化参数:
nThreads:DEFAULT_EVENT_LOOP_THREADS//默认当前CPU逻辑核心数的两倍,
selectorProvide:SelectorProvider.provider()//当前JVM中唯一的一个单例的provider,
SelectStrategyFactory:DefaultSelectStrategyFactory.INSTANCE//默认选择策略工厂实例
chooserFactory:DefaultEventExecutorChooserFactory.INSTANCE//选择器工厂实例
重点方法是MultithreadEventExecutorGroup的构造方法分析
首先判断初始化构造函数中的Executor函数,当其为空时,将其初始化
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());首先newDefaultThreadFactory()创建默认的线程工厂,然后创建ThreadPerTaskExecutor线程Executor对象
(此时创建的Executor是NioEventLoopGroup内创建的Executor对象,并非NioEventLoopGroup本身,可称为总Executor对象)
随后创建children数组,根据需要创建的线程数创建对应数量的数组
children = new EventExecutor[nThreads]; 因为每个NioEventLoopGroup都是NioEventLoop集合的元素,所以此时的children数组就是当前NioEventLoopGroup的NioEventLoop
所以NioEventLoop的创建是在NioEventLoopGroup初始化的时候
NioEventLoop初始化:整个过程存在一个成功标志,catch每个NioEventLoop创建完成过程,如果发生异常,则将所有已创建的NioEventLoop关闭。
参考资料:https://blog.csdn.net/zhangzehai2234/article/details/135175994 (tomcat和netty对比)
https://blog.csdn.net/weixin_40909461/article/details/138355959 (netty入门)
https://blog.csdn.net/qq_35190492/article/details/113174359 (netty知识点汇总)
netty
最新推荐文章于 2024-09-30 10:54:33 发布