1.Netty源码-Reactor线程模型之NioEventLoopGroup研究
2.Netty源码-一分钟掌握4种tcp粘包解决方案
3.Nettyåç-ä»NIOå¼å§
4.netty源码解析(三十五)---Netty启动3 成功bind 等待连接
5.Netty源码-Sharable注解,码入我猜你理解错了!码入
6.跟着源码学IM(九):基于Netty实现一套分布式IM系统
Netty源码-Reactor线程模型之NioEventLoopGroup研究
在Netty网络编程中,码入NioEventLoopGroup作为线程池的码入核心组件,其作用至关重要。码入从初始化的码入论文检索源码逻辑分析来看,NioEventLoopGroup扮演多重角色,码入不仅提供了线程池相关功能,码入同时也继承了线程模型的码入ScheduledExecutorService,ExecutorService和Executor接口,码入体现其多功能性。码入
其层次结构显示,码入NioEventLoopGroup从底层向上层层封装,码入实现了线程池模型的码入关键功能。进一步深入分析,码入NioEventLoopGroup通过继承自MultithreadEventLoopGroup,并在构造函数中执行关键初始化操作,展现了其独特的设计。首先,NioEventLoopGroup在初始化时创建线程工厂,构建线程执行器Executor,故事平台 源码如果未提供自定义Executor,将使用DefaultThreadFactory创建FastThreadLocalThread线程执行任务。其次,根据指定数量nThreads创建子线程组,若nThreads未定义或设为0,则默认设置为2倍的CPU线程数。最后,在初始化子线程组时,NioEventLoopGroup通过newChild()方法执行初始化,这一步操作具体实现由NioEventLoop类完成,其初始化参数包括线程选择器chooser,以及其他多个关键参数,确保线程高效运行。
NioEventLoopGroup与Java线程池之间的区别主要体现在其面向特定应用场景的设计上,尤其在事件驱动和非阻塞IO模型的支持方面。Netty通过NioEventLoopGroup实现了更灵活、高效的并发处理机制,使得在处理高并发、高网络流量场景时,性能得到显著提升。aspnet分块源码
在研究NioEventLoopGroup的过程中,我们深入学习到了设计模式的应用,如单例模式确保了线程选择器的唯一性,工厂模式则负责创建不同类型的线程组。此外,模板设计模式的使用,使得NioEventLoopGroup能够提供高度抽象的初始化逻辑,同时保持了代码的复用性和可扩展性。通过这种设计,Netty不仅优化了资源管理,还提升了系统的整体性能和稳定性。
Netty源码-一分钟掌握4种tcp粘包解决方案
TCP报文的传输过程涉及内核中recv缓冲区和send缓冲区。发送端,数据先至send缓冲区,经Nagle算法判断是否立即发送。接收端,数据先入recv缓冲区,再由内核拷贝至用户空间。
粘包现象源于无明确边界。解决此问题的充电收费源码关键在于界定报文的分界。Netty提供了四种方案来应对TCP粘包问题。
Netty粘包解决方案基于容器存储报文,待所有报文收集后进行拆包处理。容器与拆包处理分别在ByteToMessageDecoder类的cumulation与decode抽象方法中实现。
FixedLengthFrameDecoder是通过设置固定长度参数来识别报文,非报文长度,避免误判。
LineBasedFrameDecoder以换行符作为分界符,确保准确分割报文,避免将多个报文合并。
LengthFieldPrepender通过设置长度字段长度,实现简单编码,为后续解码提供依据。
LengthFieldBasedFrameDecoder则是一种万能解码器,能够解密任意格式的编码,灵活性高。
实现过程中涉及的参数包括:长度字段的起始位置offset、长度字段占的字节数lengthFieldLength、长度的调整lengthAdjustment以及解码后需跳过的字节数initialBytesToStrip。
在实际应用中,指标源码集合为自定义协议,需在服务器与客户端分别实现编码与解码逻辑。服务器端负责发送经过编码的协议数据,客户端则接收并解码,以还原协议信息。
Nettyåç-ä»NIOå¼å§
Nettyæ¯åºäºNIOçå¼æ¥éä¿¡æ¡æ¶ï¼æ¾ç»å¼å ¥è¿AIOï¼åæ¥æ¾å¼ï¼ï¼æ è¦è¯´Nettyåçæ们è¦å ä»NIOå¼å§ã
NIO æ¯JAVAå¨JDK4ä¸å¼å ¥çåæ¥éé»å¡é信模åï¼å¨NIOåºç°ä¹åï¼JDK4ä¹åï¼å¸åºä¸åªæä¸ä¸ªBIO模å顾åæä¹BLOCKING IO ï¼åæ¥é»å¡é信模åï¼
BIOï¼BLOCKING I/Oï¼ï¼
BIO 为ä¸ä¸ªè¿æ¥ ä¸ä¸ªçº¿ç¨ç模å¼ï¼å½æè¿æ¥æ¶æå¡å¨ä¼å¼å¯ä¸ä¸ªçº¿ç¨æ¥å¤ç请æ±
è¥æ¤è¯·æ±å¥é½ä¸æ³å¹²æ¤æ¶çº¿ç¨ä¼æä¹æ ·ï¼
æ¤çº¿ç¨ä¼è¿å ¥é»å¡æ¨¡å¼ï¼BLOCKINGï¼ï¼---å¥ä¹ä¸å¹²ï¼å¹²ççzzZZ~
è¿ç§ä¸è¿æ¥ï¼ä¸çº¿ç¨ç模å¼ä¼é ææå¡å¨èµæºä¸å¿ è¦çå¼é并ä¸å¨å¤§éè¿æ¥è®¿é®æ¶ æå¡å¨ä¼åçä»ä¹ï¼è½¦éï¼çº¿ç¨ï¼ä¸è¶³ï¼è½¦å¤ªå¤--æå µè½¦äº
ç±æ¤å°±åºç°äºNIO
â
NIOï¼new/NONBLOCKING I/Oï¼:
NIO为åæ¥éé»å¡é信模åï¼Selectï¼å¤è·¯å¤ç¨å¨ï¼ä¸ºæ¤æ¨¡åçæ ¸å¿ï¼å®ç°äºå¤ä¸ªè¿æ¥ä¸ä¸ªçº¿ç¨
å½æ客æ·ç«¯è¿æ¥è¯·æ±æ¶ æ¤è¿æ¥è¯·æ±ä¼è¢«æ³¨åè³selectä¸ï¼å½selectæ£æµå°æ¤è¿æ¥æI/O请æ±æ¶æä¼æå¼ä¸ä¸ªçº¿ç¨å»å¯¹æ¤I/O请æ±è¿è¡å¤ç-----å线ç¨æ¨¡å
è¿ä¸ªæ¶åæ人é®äºï¼è¿ä¹å¤æä½é½å¨ä¸ä¸ªçº¿ç¨éï¼çº¿ç¨å¿ä¸è¿æ¥æä¹åï¼
æ¤æ¶ ç±äºç½ç»è¯·æ±ãI/O读åãä¸å¡æä½é½å¨ä¸ä¸ªçº¿ç¨ä¸ï¼ä¼å¯¼è´å¨é«å¹¶åçæ åµä¸åå¨æ§è½ç¶é¢ äºæ¯ä¹æ人就æåºæ¥ å°ä¸å¡æä½ä¸¢å°å¦ä¸ä¸ªçº¿ç¨æä¹æ ·ï¼
äºæ¯åºç°äºç¬¬ä¸ç§reactor模å-使ç¨çº¿ç¨æ± è¿è¡æä½ç½ç»è¯·æ±ãIOå¨ä¸ä¸ªçº¿ç¨ï¼ä¸å¡æä½å¨å¦ä¸ªä¸ä¸ªçº¿ç¨ çä¸å¡å离----线ç¨æ± 模å
ä»æ¤å¾ä¸å¯ä»¥çåºæ¤æ¶ 模åä¸ä½¿ç¨ä¸ä¸ªçº¿ç¨æ± æ¥è¿è¡ç½ç»è¯·æ±ãIO读å
å½è¯»åå®æåå°ä¸å¡æä½ç»å®å¨çº¿ç¨æ± ä¸å¦å¤ç线ç¨ä¸-------ç½ç»IOä¸ä¸å¡æä½å¯ä»¥åæ¥è¿è¡äºï¼ä¸åé½å®ç¾äºèµ·æ¥ï¼
ä½æ¯ï¼äºæ è¿æ²¡å®ï¼ï¼è¿ä¸ªæ¶ååæ人æåºé®é¢ï¼å¨é«å¹¶åçæ¶åååï¼ä¼ä¸ä¼ææ§è½ç¶é¢
å 为ç½ç»IOæ¯é常æ¶èCPUçï¼å½ç½ç»è¯·æ±ä¸ç½ç»IOå¨å个线ç¨ä¸æ¶ï¼é CKçæ åµä¸å个线ç¨å¹¶ä¸è¶³ä»¥æ¯æèµ·ææçIOæä½ï¼å æ¤ä¹å½¢æäºå¨é«å¹¶åç¶æä¸çæ§è½ç¶é¢
äºæ¯å¤§ä½¬ä»¬å°±æ³çï¼å¦ææIOæåºæ¥è®©å个线ç¨æ± å»æ¥æ¶ç½ç»è¯·æ±ï¼ç¨å¦ä¸ä¸ªçº¿ç¨æ± æ¥è¿è¡IOä¸ä¸å¡æä½ä¼ä¸ä¼æ´å¥½
äºæ¯ç¬¬åç§Reactor模ååºè¿èç--主ä»Reactorå¤çº¿ç¨æ¨¡å
æ¤æ¨¡åä¸ mainReactoråªç¨äºæ¥æ¶ç½ç»è¯·æ±ï¼èsubReactorä¸ä¸ºä¸ä¸ªçº¿ç¨æ± ï¼çº¿ç¨æ± ä¸æ¯ä¸ªçº¿ç¨ä¸ç»å®ä¸ä¸ªselect
å½mainReactoræ¥æ¶å°è¯·æ±æ¶ï¼ä¸ä¸ªæè¿°ç¬¦ï¼ ç³»ç»ä¼çæä¸ä¸ªæ°çæ述符代表æ¤è¿æ¥çæï¼æ¤æ¶mainReactorä¼å°æ°çæ述符éè¿ä¸ä¸ªç®æ³å¨çº¿ç¨æ± ä¸éå®ä¸ä¸ªçº¿ç¨ å°æ¤æ述符ç»å®è³æ¤çº¿ç¨æ± ä¸çselectä¸ï¼ç±æ¤çº¿ç¨æ¥å¯¹è¯·æ±è¿è¡I/O ä¸ä¸å¡æä½
ä»æ¤ç¾ä¸è¿æ¥é«å¹¶åä¸æ¯é®é¢
åå°è¿ æ们æ¯ä¸æ¯æ³èµ·äºNettyçå¯å¨è¿ç¨
1ã声æ两个EventLoopGroupä¸ä¸ªä¸ºbossï¼mainReactorï¼ä¸ä¸ªä¸ºworkerï¼subReactorï¼
EventLoopGroupï¼çº¿ç¨æ± ï¼åå§åçæ¶åä¼çæï¼æå è½½ï¼æå®æ°éçEventLoopï¼çº¿ç¨ï¼è¥æ æå® åä¼çæCPUæ°X2ç线ç¨
2ã声æä¸ä¸ªå¯å¨è¾ å©ç±»Bootstrap并å°EventLoopGroup注åå°å¯å¨è¾ å©ç±»BootStrapä¸(bootStrap.group)
æ¥çåç»bootstrapæå®channel模åçå±æ§ï¼åæ·»å ä¸ä¸å¡æµæ°´çº¿ï¼channelpipelineï¼å¹¶ä¸å¨pipelineä¸æ·»å ä¸ä¸å¡æä½handlerï¼ï¼éè¿channelpipelineå¯ä»¥å¯¹ä¼ å ¥æ°æ®ä¸ºæ欲为ï¼
3ãç»å®ç«¯å£
Nettyå¯å¨å®æ
è¿æ¶åå¯è½æ人ä¼é®äºï¼è¿åä½ ä¸é¢è¯´çreactorï¼NIOæå¥å ³ç³»ï¼
è¿ä¸ªæ¶åæ们è¦è¿ä¹ç
â
è¥æ们å°bossä¸worker线ç¨æ± 设置为ç¸åçä¸ä¸ªçº¿ç¨æ± ï¼é£ä¹ä¼åçä»ä¹äºï¼
æ¤æ¶å ³æ³¨ä¸ä¸ç¬¬ä¸ä¸ªReactor模åæ¶å°±ä¼åç° å½BOSS=WORKERæ¶å nettyå®ç°çå°±æ¯ç¬¬ä¸ç§Reactor模å 使ç¨çº¿ç¨æ± 模å
èå½bossä¸çäºworkerçæ¶å使ç¨çå°±æ¯ç¬¬åç§ ä¸»ä»å¤çº¿ç¨æ¨¡å
Nettyå°±æ¯åºäºReactor模åæ¥å¯¹NIOè¿è¡äºæç¨åå°è£ ï¼ä»Nettyæºç ä¸å°±å¯ä»¥çåºæ¥å ¶å®åºå±è¿é½æ¯NIOçæ¥å£
æ¤æ¬¡å¤ä¸ºèªå·±è¯»æºç ä¹åçç解 å¦æ误请ææ£
ææ©
åææ¿ä¸ç¬¬ä¸ä¸ªèµ
netty源码解析(三十五)---Netty启动3 成功bind 等待连接
Netty启动过程中的bind操作在AbstractBootstrap类中启动,由于异步特性,ChannelFuture在register0方法后交给事件执行器处理,此时isDone返回为false。在sync同步等待时,主线程会阻塞在PendingRegistrationPromise上,等待绑定完成。
PendingRegistrationPromise的创建和ChannelFuture的监听器是为了在绑定成功后执行后续操作。当bind0方法中的safeSetSuccess成功后,会触发监听器,进一步调用AbstractChannel的bind方法。这个过程会通过DefaultChannelPipeline的tail处理,最后在AbstractChannelHandlerContext的HeadContext中,调用handler的bind方法,其中HeadContext的unsafe.bind方法会调用到NioServerSocketChannel的unsafe的dobind方法。
在NioServerSocketChannel中,真正的绑定操作是调用原生的jdk的bind方法。当绑定成功后,AbstractChannel的dobind方法会设置promise为success,从而唤醒主线程,继续执行后续代码。至此,Netty的bind操作等待连接的到来。
总结整个流程:Bootstrap创建Promise等待,然后通过管道传递到AbstractChannel,通过HeadContext调用unsafe.bind,最终在NioServerSocketChannel中调用原生bind,主线程等待并处理bind结果。当连接到来时,整个绑定过程结束。
Netty源码-Sharable注解,我猜你理解错了!
学习目标
理解Sharable注解在Netty中的作用。个人臆想,只要在ChannelHandler上添加了@ChannelHandler.Sharable注解,所有的channel都共享这一个ChannelHandler实例。真是这样的吗?如果你认为所有channel共享一个pipeline,只能说明你对pipeline的初始化不理解。你臆想完全错误!!!
Sharable注解介绍
在深入探讨之前,建议阅读《Netty源码-ChannelPipeline的剖析》。阅读后,问题迎刃而解。同时,你可能还会疑惑Sharable注解的用途。它的主要目的是在pipeline之间共享信息,例如统计连接数、限流、白名单等。
如何使用Sharable注解
源码中有明确说明,你可以在ChannelHandler的成员变量上使用@ChannelHandler.Sharable注解,表示这个变量的实例可以被所有pipeline共享。如果不想共享,就每次创建新实例。通过代码示例可以直观理解共享实例和每次创建新实例的区别。
使用场景
Sharable注解适用于在pipeline之间需要共享数据或状态的场景。例如统计连接数、限流、白名单管理等。
注意事项
使用Sharable注解时,务必考虑线程安全。在多线程环境中,确保共享数据的正确性和一致性。
实战应用-统计当前连接数
通过实践,我们实现了一个简单的统计当前连接数的示例。执行结果如下:
Connected to the target VM, address: '.0.0.1:', transport: 'socket' count:1 InBoundHandler1-channelRead:abc InBoundHandler1-channelRead:asd count:2 InBoundHandler1-channelRead:abc InBoundHandler1-channelRead:asd
跟着源码学IM(九):基于Netty实现一套分布式IM系统
本文作者小傅哥,以实践为导向,带你开发分布式即时通讯(IM)系统。通过动手实践,理解DDD+Netty技术的运用。
多次实践即时通信项目后,这次将分享具体步骤和源码,涵盖系统架构、通信协议、用户操作(单聊、群聊、表情发送)等。代码实战贯穿始终,从UI事件驱动设计到系统架构拆分,如UI与业务逻辑分离,便于扩展和维护。
知识准备方面,Netty是Java的高效网络编程框架,简化网络应用开发。对基础知识有需求的,推荐阅读相关入门文章。系统运行效果和源码下载链接可以在文中找到。
系统设计采用DDD模式,易于操作和管理。UI设计包括聊天窗口、好友列表和事件驱动。通信设计上,我们探讨了系统架构选择和通信协议设计,如添加好友和消息应答的处理示例。
后续内容包括网络连接的断线重连机制,集群通信的实现,以及整个项目的技术栈应用,如Netty、SpringBoot、Mybatis等。通过源码学习,掌握从HelloWorld到深度挖掘的完整过程。
系列文章链接在文中列出,供进一步学习。对于希望深入理解IM开发的读者,务必结合源码进行实践,才能收获满满。本文是系列中的第九篇,提供丰富的实践资料和参考资料。