netty

Netty源码学习系列④接收消息

Netty源码学习系列④接收消息

有点开始怀疑人生。为什么我说不清楚netty的工作方式?博客基本上是自己一个字一个字敲出来的,也能在一定程度上说明,我当时确实是懂了,但为什么会说不出来呢?回顾了自己的博客,有些过程的细节确实忘了,但是可怕的是,我需要想半天才能想起来,有些还想不起来。我觉得方式有问题,单纯的文字记录,缺少指导性的图画,不利于理解整个流程。 接收客户端的消息,很明显是从Main Reactor所在的EventLoop的for循环中,通过select()获取到了OP_READ事件。 Update - 2020.3.23 Netty整个系列先暂停学习,我觉得目前应该学习的是Spring的一些更加深入的知识,不然有一种眼高手低的感觉,踏踏实实地把web的那一套先搞清楚。

6 | Netty:新连接的建立

6 | Netty:新连接的建立

当服务端启动好了之后,也就是说,服务端已经在执行NioEventLoop的一个死循环方法run()中,一直轮询事件,并且此时的监听的事件为OP_ACCEPT。如果有新连接接入,那么首先会在上述的run()方法中触发... 收到新的连接 首先,服务端启动好了之后,会进入等待事件的状态,也就是调用JDK的NIO的API: // NioEventLoop.java -> run() if (!hasTasks()) { strategy = select(curDeadlineNanos); } // 核心是调用jdk的api selector.select(); 收到新的连接后,将会通过processSelectedKeys()进行处理,处理内容包括:创建、初始化NioSocketChannel。 // NioEventLoop.java private void processSelectedKeys() { if (selectedKeys != null) { processSelectedKeysOptimized(); } els

5 | Netty:服务端启动流程分析

5 | Netty:服务端启动流程分析

目前对于Netty的理解是:一套完善了Java NIO操作的框架,因为Netty的最底层还是调用jdk的nio相关的API,但是又在jdk的nio基础上做了很多的封装,并衍生出来了自己相关的概念。 服务启动的主线操作 以EchoServer为例,一条可参考的服务启动的主线操作如下: main thread 1. 创建selector 2. 创建serversocketchannel 3. 初始化serversocketchannel 4. 给serversocketchannel从bossgroup中选择一个NioEventLoop boss thread 1. 将serversocketchannel注册到选择的NioEventLoop的selector 2. 绑定地址启动 3. 注册接受连接事件(OP_ACCEPT)到selector上 对应到代码中的操作依次为: // 1. 创建selector Selector selector = sun.nio.ch.SelectorProviderImpl.openSelector(); // 2. 创建s

4 | Netty:JavaNIO概览

4 | Netty:JavaNIO概览

在正式开始Netty相关的学习之前,我决定还是要先回顾一下Java NIO,至少要对Java NIO相关的概念有一个了解,如Channel、ByteBuffer、Selector等。要自己动手写一写相关的demo实例、并且要尽可能地去了解其后面是如何实现的,也就是稍微看看相关jdk的源代码。 Java NIO 由以下几个核心部分组成:Buffer, Channel, Selector。传统的IO操作面向数据流,面向流 的 I/O 系统一次一个字节地处理数据,意味着每次从流中读一个或多个字节,直至完成,数据没有被缓存在任何地方;NIO操作面向缓冲区( 面向块),数据从Channel读取到Buffer缓冲区,随后在Buffer中处理数据。 Buffer 可以理解成煤矿里面挖煤的小车,把煤从井底运地面上面。它的属性与子类如下: Buffer是一个抽象类,继承自Object,拥有多个子类。此类在JDK源码中的注释如下: A container for data of a specific primitive type. A buffer is

3 | Netty:源代码导入IDEA

3 | Netty:源代码导入IDEA

Netty源代码导入IDEA时需要注意的地方 操作系统 64位 版本问题 官网上面说可以用64-bit OpenJDK 8 or above 。没有尝试OpenJDK,Oracle的JDK要1.8版本的。源码里面用到了Unsafe这个类,在jdk1.8之后的版本中被移除掉了。 IDEA的位数保持与操作系统位数相同 操作流程 1. 最好先设置好maven的镜像,导入时需要拉取很多jar包。 2. 打开IDEA,选择Import Project,选择好netty源码目录后再选择maven。 3. 等待Import完成,找到EchoServer,跑main方法,这时会报错,按照如下方式操作即可。 如果用的不是jdk1.8以上的jdk,会报Unsafe找不到,这种情况只需要在Project Structure中将Project SDK设置成jdk1.8即可。 如果是io.netty.util.collection.LongObjectMap找不到之类的错误,可以在netty-common模块中执行mvn clean compile,可以按下图方式进行操作该指令。

2 | Netty:Reactor与Netty之间的关系

2 | Netty:Reactor与Netty之间的关系

今天是2020年2月2号,感觉是一个比较特殊的日子,今天就来一篇记录型的博客吧,哈哈 起初很好奇,到底什么叫Reactor模式,这个名词感觉特别高大上,然后看描述,虽然能看懂描述,但是却不是特别明白到底是什么意思。这个时候主要是没有形成一种直观的印象,直观的印象就是比如说苹果,再给你看个实物,你就能把苹果与关联起来。在学习netty的时候,也遇到了Reactor模式,于是有了机会来形成一种比较直观的印象。 什么是Reactor模式? 定义看起来很抽象,但是其实很好理解。**它是一种开发模式,模式的核心流程:注册感兴趣的事件 -> 扫描是否有感兴趣的事件发生 -> 事件发生后做出相应的处理。**仅此而已。使用BIO开发的时候,每有一个新的请求过来了,都会新开一个线程,然后在新的线程里面进行业务处理,这种处理方式就是Thread-Per-Connection; 所以对应起来,使用NIO开发的时候,也有一个模式去处理相应的请求与业务逻辑,叫做Reactor模式。至于具体怎么做,也就是前面提到的Reactor模式的核心流程。 Reactor模式的3种版本 开始这个之前我有一

1 | netty:粘包与拆包的处理

1 | netty:粘包与拆包的处理

TCP是个流协议,流是一串没有界限的数据。TCP会根据TCP缓冲区的实际情况对包进行划分。因此造成一个完整的业务包,会被TCP分成多个包、把多个包封装成一个大的包进行发送。 粘包与拆包现象 服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包; 服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包; 服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包; 服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1包的剩余内容D1_2和D2包的整包。 产生原因 应用程序write写入的字节大小/大于套接口发送缓冲区大小; 进行MSS大小的TCP分段; 以太网帧的payload大于MTU进行IP分片。 对于Linux,发送缓冲区的默认值为:16384。可使用下面命令查看: # 接收 cat /proc/sys/net/ipv4/tcp_rmem # min default max # 4096 87380 6291456

两个Netty入门用法Demo

两个Netty入门用法Demo

大概一年多前,用过Netty做局域网内自动组网,但是当时的主要代码不是我写的,并且时间过了很久,忘得差不多了,然而发现Netty确实是一个很有意思的框架,值得去深入研究、学习。本文的例子,之前也看过、写过,在各种介绍Netty的书籍中都有看到,并且Netty的官方文档也有这样的例子。 EchoServer Netty官方Echo例子,其实在源码中也有该例子。 EchoServer import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.