1 Star 0 Fork 0

也不过如此 / netty

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

Netty学习记录

模块介绍

  1. netty-bio: 阻塞型网络通信demo。
  2. netty-nio: 引入channel(通道)、buffer(缓冲区)、selector(选择器)的概念,采用事件驱动的方式,使用单个线程就可以监听多个客户端通道,改进bio模式下线程阻塞等待造成的资源浪费。
  3. netty-demo: netty小demo,认识netty初体验。
  4. netty-groupchat: 使用netty编写一个群聊系统。
  5. netty-http: netty的http调用demo。
  6. netty-bytebuf: netty缓冲区使用demo。
  7. netty-decoder: netty编解码,handler调用链使用示例。
  8. netty-idlestate: netty心跳包使用示例。
  9. netty-sticking: 自定义协议与handler,解决tcp传输粘包与拆包问题。
  10. netty-rpc: 使用netty自定义实现rpc通信。

netty-bio模块

模拟测试采用socker的bio方式进行网络通信。

blocking io:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情就会进入阻塞等待状态,造成不必要的线程开销。

适用于连接数据小且连接固定的系统架构。

架构示意图: img.png

netty-nio模块

non-blocking io:同步非阻塞,在bio的架构上进行改进,引入channel(通道)、buffer(缓冲区)、selector(选择器)的概念,采用事件驱动的方式,使用单个线程就可以监听多个客户端通道,改进bio模式下线程阻塞等待造成的资源浪费。

架构示意图: img.png

关键:select会根据不同的事件,在各个channel通道上进行切换。

缓冲区buffer

本质上是一个可以读写数据(关键)的内存块,nio的读取与写入数据都必须是经过buffer的。

通道channel

把通道看做流、把通道看做流、把通道看做流,重要的事情说三遍,会很好理解。 nio引入的通道类似bio中流的概念,不同之处在于:

  • 通道可以同时进行读写操作,而流只能读或者写
  • 通道可以实现异步读写数据
  • 通道可以从缓冲区读数据,也可以写数据到缓冲区(双向的概念)

NIOFileOper01: 本地文件写数据

使用ByteBuffer与FileChannel,将“hello,李嘉图”NIOFileOper01.txt文件中。

NIOFileOper02: 本地文件读数据

使用ByteBuffer(缓冲) 和 FileChannel(通道), 将 NIOFileOper01.txt 中的数据读入到程序,并显示在控制台屏幕

NIOFileOper03: 使用一个Buffer完成文件读取

使用 FileChannel(通道) 和 方法 read , write,完成文件的拷贝

NIOFileCopy:拷贝文件 transferFrom 方法

使用 FileChannel(通道) 和 方法 transferFrom ,完成文件的拷贝

选择器Selector

核心:selector能够检测多个注册的通道上是否有事件发生(多个channel以事件的方式可以注册到同一个selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。 这样就可以做到只使用一个单线程去管理多个通道。

只有在连接/通道真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程。

原理图: img.png

说明:

  1. 当客户端连接时,会通过ServerSocketChannel得到SocketChannel。
  2. Selector进行监听select方法,返回有事件发生的通道的个数。
  3. 将socketChannel注册到Selector上,register(),一个selector上可以注册多个SocketChannel。
  4. 注册后返回一个selectionKey,会和该selector关联。
  5. 进一步得到各个selectionKey(有事件发生)。
  6. 再通过selectionKey反向获取socketChannel,方法channel()。
  7. 可以通过得到的channel,完成业务逻辑。

netty概述

异步的基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠的网络IO程序。 img.png 有了NIO为什么还需要Netty?

不需要过于关注底层的逻辑,对下面的sdk等进行封装,相当于简化和流程化了NIO的开发过程。spring和springboot的关系差不多。

因为 Netty 5出现重大bug,已经被官网废弃了,目前推荐使用的是Netty 4.x的稳定版本。

Netty高性能架构设计

线程模型基本介绍

img.png

传统阻塞 I/O 服务模型

img.png 模型特点:

  • 采用阻塞IO模式获取输入的数据
  • 每个连接都需要独立的线程完成数据的输入,业务处理,数据返回

问题分析:

  • 当并发数很大,就会创建大量的线程,占用很大系统资源
  • 连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在read操作,造成线程资源浪费

Reactor 模式

I/O 复用结合线程池,就是 Reactor 模式基本设计思想。 img.png Reactor在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对IO事件作出反应。它像公司的电话接线员,接听来自客户的电话并将线路转译到适当的联系人。

单 Reactor 单线程

img.png

  • 优点:模型简单,没有多线程、进程通信、竞争问题,全部都在一个线程中完成。
  • 缺点:性能问题,只有一个线程,无法完全发挥多核CPU性能。Handler在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈。

单 Reactor 多线程

img.png 在上一代的问题上进行修改,Reactor主线程只负责响应事件,不做具体的业务处理,通过read读取数据后,会分发给后面的worker线程池的某个线程处理业务。

  • 优点:充分利用多核CPU的处理能力。
  • 缺点:多线程数据共享和访问比较复杂,Reactor处理所有的事件监听与响应,在单线程运行,在高并发场景容易出现性能瓶颈。

主从 Reactor 多线程

针对单 Reactor 多线程模型中,Reactor 在单线程中运行,高并发场景下容易成为性能瓶颈,可以让 Reactor 在多线程中运行。 img.png Reactor主线程MainReactor对象通过select监听连接事件,收到事件后,通过Acceptor处理连接事件。当Acceptor处理连接事件后,MainReactor将连接分配给 SubReactor,SubReactor将连接加入到连接队列进行监听,并创建Handler进行各种事件处理。

  • 优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理,无需返回数据给主线程。
  • 缺点:编程复杂度较高。

Reactor模式小结

  1. 单Reactor单线程,前台接待员和服务员是同一个人,全程为客户服务。
  2. 单Reactor多线程,1个前台接待员,多个服务员,接待员只负责接待。
  3. 主从Reactor多线程,多个前台接待员,多个服务生。

Netty 模型

img.png

  • Netty抽象出两组线程池,BossGroup专门负责接收客户端的连接,WorkerGroup专门负责网络的读写。
  • 每个worker nioEventLoop处理业务时,会使用pipeline(管道),pipeline中包含了channel,即通过pipeline可以获取到对应通道,管道中维护了很多的处理器。

异步模型

基本介绍

  • 异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的组件完成后,通过状态、通知和回调来通知调用者。
  • Netty中的I/O操作是异步的,包括Bind、Write、Connect等操作会简单的返回一个 ChannelFuture
  • 调用者不能立刻获得结果,而是通过 Future-Listener机制,用户可以方便地主动获取或者通过通知机制获得I/O操作结果。
  • Netty的异步模型是建立在future和callback(回调)之上的。重点是future,它的核心思想:假设一个方法func,计算过程可能非常耗时,等待func返回显然不合适。那么在 调用func的时候,立刻返回一个future,后续可以通过future去监控方法func的处理过程(即:Future-Listener机制)
    • ChannelFuture是一个接口:Public interface ChannelFuture extends Future
    • 可以添加监听器,当监听的事件发生时,就会通知到监听器。
  • 在使用Netty进行编程时,拦截操作和转换出入站数据只需要你提供callback或利用future即可。这使得链式操作简单、高效、并有利于编写可重用、通用的代码。

Future-Listener机制

当Future对象刚刚创建好时,处于非完成状态,调用者可以通过返回的channelFuture来获取操作执行的状态,注册监听函数来执行完成后的操作。

常见的操作:

  • 通过 isDone 方法来判断当前操作是否完成。
  • 通过 isSuccess 方法来判断已完成的当前操作是否成功。
  • 通过 getCause 方法来获取已完成的当前操作失败的原因。
  • 通过 isCancelled 方法来判断已完成的当前操作是否被取消。
  • 通过 addListener 方法来注册监听器,当操作已完成(isDone),将会通知指定的监听器。

小结:相比于传统阻塞I/O,执行I/O操作后线程会被阻塞住,直到操作完成。异步处理的好处是不会造成线程阻塞,线程在I/O操作期间可以执行别的程序,在高并发情形下会 更稳定和更高的吞吐量。

Netty 核心模块组件

ServerBootstrap、Bootstrap

Bootstrap意思是引导,一个Netty应用通常由一个Bootstrap开始,主要作用是配置整个Netty程序,串联各个组件,Netty中Bootstrap类是客户端程序的启动引导类, ServerBootstrap是服务器启动引导类。

常用方法:

  • public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup):用于服务器端,用来设置两个EventLoop
  • public B group(EventLoopGroup group):该方法用于客户端,用来设置一个EventLoop
  • public B channel(Class<? extends C> channelClass):该方法用来设置一个服务器端的通道实现
  • public B option(ChannelOption option, T value):用来给ServerChannel添加配置
  • public ServerBootstrap childOption(ChannelOption childOption, T value):用来给接收的通道添加配置
  • public ServerBootstrap childHandler(ChannelHandler childHandler):业务处理类,自定义handler
  • public ChannelFuture bind(int inetPort):用于服务器端,用来设置占用的端口号
  • public ChannelFuture connect(String inetHost, int inetPort):用于客户端,用来连接服务器端

Future、ChannelFuture

Netty中所有的IO操作都是异步的,不能立刻得知消息是否被正确处理。但是可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFuture, 他们可以注册一个监听,当操作执行成功或失败时监听会自动触发注册的监听事件

常用的方法:

  • Channel channel():返回当前正在进行IO操作的通道
  • ChannelFuture sync():等待异步操作执行完毕

Channel

Netty网络通信的组件,能够用于执行网络 I/O 操作。 通过 Channel 可获得当前网络连接的通道的状态。 通过 Channel 可获得 网络连接的配置参数 (例如接收缓冲区大小)。 Channel 提供异步的网络 I/O 操作(如建立连接,读写,绑定端口),异步调用意味着任何 I/O 调用都将立即返回,并且不保证在调用结束时所请求的 I/O 操作已完成 调用立即返回一个 ChannelFuture 实例,通过注册监听器到 ChannelFuture 上,可以 I/O 操作成功、失败或取消时回调通知调用方。 不同协议、不同的阻塞类型的连接都有不同的 Channel 类型与之对应,常用的 Channel 类型:

  • NioSocketChannel,异步的客户端 TCP Socket 连接。
  • NioServerSocketChannel,异步的服务器端 TCP Socket 连接。
  • NioDatagramChannel,异步的 UDP 连接。
  • NioSctpChannel,异步的客户端 Sctp 连接。
  • NioSctpServerChannel,异步的 Sctp 服务器端连接,这些通道涵盖了 UDP 和 TCP 网络 IO 以及文件 IO。

实际开发过程中,在拿到channel之后,做一个判断,看是什么连接,如(channel instanceof SocketChannel/DatagramChannel),就可以做不同的业务处理。

Selector

Netty基于Selector对象实现I/O多路复用,通过Selector一个线程可以监听多个连接的Channel事件。当向一个Selector中注册Channel后, Selector内部的机制就可以自动不断地查询(Select)这些注册的Channel是否有已就绪的I/O事件(例如可读,可写,网络连接完成等), 这样程序就可以很简单地使用一个线程高效地管理多个Channel。

ChannelHandler 及其实现类

ChannelHandler是一个接口,处理 I/O 事件或拦截 I/O 操作,并将其转发到其 ChannelPipeline(业务处理链)中的下一个处理程序

ChannelHandler及其实现类一览图: img.png

  • ChannelInboundHandler 用于处理入站 I/O 事件。
  • ChannelOutboundHandler 用于处理出站 I/O 操作。
  • ChannelInboundHandlerAdapter 用于处理入站 I/O 事件。
  • ChannelOutboundHandlerAdapter 用于处理出站 I/O 操作。
  • ChannelDuplexHandler 用于处理入站和出站事件。

Pipeline 和 ChannelPipeline

ChannelPipeline 是一个 Handler 的集合,它负责处理和拦截 inbound 或者 outbound 的事件和操作,相当于一个贯穿 Netty 的链。(也可以这样理解:ChannelPipeline 是 保存 ChannelHandler 的 List,用于处理或拦截 Channel 的入站事件和出站操作)。

ChannelPipeline 实现了一种高级形式的拦截过滤器模式,使用户可以完全控制事件的处理方式,以及 Channel 中各个的 ChannelHandler 如何相互交互。

在 Netty 中每个 Channel 都有且仅有一个 ChannelPipeline 与之对应,它们的组成关系如下: img.png 一个 Channel 包含了一个 ChannelPipeline,而 ChannelPipeline 中又维护了一个由 ChannelHandlerContext 组成的双向链表,并且每个 ChannelHandlerContext 中又关联着一个 ChannelHandler。

入站事件和出站事件在一个双向链表中,入站事件会从链表 head 往后传递到最后一个入站的 handler,出站事件会从链表 tail 往前传递到最前一个出站的 handler,两种类型的 handler 互不干扰。

常用方法:

  • ChannelPipeline addFirst(ChannelHandler... handlers),把一个业务处理类(handler)添加到链中的第一个位置。
  • ChannelPipeline addLast(ChannelHandler... handlers),把一个业务处理类(handler)添加到链中的最后一个位置。

ChannelHandlerContext

保存Channel相关的所有上下文信息,同时关联一个ChannelHandler对象。ChannelHandlerContext中包含一个具体的事件处理器ChannelHandler,同时ChannelHandlerContext 中也绑定了对应的pipeline和Channel的信息,方便对ChannelHandler进行调用。

常用方法:

  • ChannelFuture close(): 关闭通道
  • ChannelOutboundInvoker flush(): 刷新
  • ChannelFuture writeAndFlush(Object msg): 将数据写到ChannelPipeline中当前ChannelHandler的下一个ChannelHandler开始处理。

ChannelOption

  • ChannelOption.SO_BACKLOG
    • 对应TCP/IP协议listen函数中的backlog参数,用来初始化服务器可连接队列大小。服务端处理客户端连接请求时顺序处理的,所以同一时间只能处理一个客户端连接。 多个客户端来的时候,服务器将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小。
  • ChannelOption.SO_KEEPALIVE
    • 一直保持连接活动状态。

EventLoopGroup 和其实现类 NioEventLoopGroup

img.png

  • BoosEventLoopGroup通常是一个单线程的EventLoop,EventLoop维护着一个注册了ServerSocketChannel的Selector实例,BossEventLoop不断轮询将连接事件分离出来。
  • 通常是OP_ACCEPT事件,然后将接收到的SocketChannel交给WorkerEventLoopGroup。
  • WorkerEventLoopGroup会由next选择其中一个EventLoop来将这个SocketChannel注册到其维护的Selector并对其后续的IO事件进行处理。

常用方法:

  • public NioEventLoopGroup(): 构造方法
  • public Future<?> shutdownGracefully(): 断开连接,关闭线程

Unpooled类

Netty提供一个专门用来操作缓冲区(即Netty的数据容器)的工具类

常用方法如下:

  • public static ByteBuf copiedBuffer(CharSequence String, Charset charset):通过给定的数据和字符编码返回一个ByteBuf对象(类似于NIO中的ByteBuffer)

Google Protobuf

img.png Netty本身自带的 ObjectDecoder 和 ObjectEncoder 可以用来实现POJO对象或各种业务对象的编码和解码,底层使用的仍然是Java序列化技术,而Java序列化技术本身效率就不高,存在如下问题:

  • 无法跨语言
  • 序列化后的体积太大,是二进制的5倍多
  • 序列化性能太低 引出新的解决方案:Google的Protobuf。 img.png

Netty编解码器和handler的调用机制

代码示例:netty-decoder模块

使用自定义的编码器和解码器来说明netty的handler调用机制

  • 客户端发送long -> 服务器
  • 服务器发送long -> 客户端

结论:

  • 不论解码器handler还是编码器handler接收的消息类型必须与待处理的消息类型一致,否则该handler不会被执行
  • 在解码器进行数据解码时,需要判断缓存区(ByteBuf)的数据是否足够,否则接收到的结果会与期望的结果可能不一致。
    • ReplayingDecoder扩展了ByteToMessageDecoder类,使用这个类,我们不必调用readableBytes()方法。参数S指定了用户状态管理的类型,其中Void代表不需要状态管理。
    • ReplayingDecoder使用方便,但它也有一些局限性:
    • 并不是所有的 ByteBuf 操作都被支持,如果调用了一个不被支持的方法,将会抛出一个 UnsupportedOperationException。
    • ReplayingDecoder 在某些情况下可能稍慢于 ByteToMessageDecoder,例如网络缓慢并且消息格式复杂时,消息会被拆成了多个碎片,速度变慢。

img.png

TCP粘包与拆包及解决方案

  • TCP是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有——成对的socket,因此,发送端为了将多个发送给接收端的包,更有效的发送给对方, 使用了优化算法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样做虽然提高了效率,但是接收端就难于分辨出完整的数据包了, 因为面向流的通信是无消息保护边界的img.png

TCP粘包与拆包解决方案

  • 使用 自定义协议 + 编解码器 来解决
  • 关键就是要解决 服务器端每次读取数据长度的问题,这个问题解决,就不会出现服务器多读或少读数据的问题,从而避免TCP粘包、拆包。

代码示例:

  • 要求客户端发送5个Message对象,客户端每次发送一个Message对象
  • 服务器端每次接收一个Message,分5次进行解码,每读取到一个Message,会回复一个Message对象给客户端

Netty 核心源码剖析

只有看过Netty源码,才能说是真的掌握了Netty框架。

判断是否为 2 的 n 次方

private static boolean isPowerOfTwo(int val) {
	return (val & -val) == val;
}

源码解析:

  • Netty启动过程源码剖析
  • Netty接受请求过程源码剖析
  • Pipeline Handler HandlerContext创建源码剖析
  • ChannelPipeline是如何调度handler的
  • Netty心跳(heartbeat)服务源码剖析
  • Netty核心组件EventLoop源码剖析
  • handler中加入线程池和Context中添加线程池的源码剖析

用Netty 自己 实现 dubbo RPC

  • RPC(Remote Procedure call) - 远程程序调用,是一个计算机通信协议。该协议允许运行与一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。
  • 两个或多个应用程序都分布在不同的服务器上,它们之间的调用都像是本地方法调用一样。
  • 常见的PRC框架有:阿里的Dubbo、Google的gRPC、Go语言的rpcx,spring的Spring cloud。 img.png RPC 的目标就是将 2-8 这些步骤都封装起来,用户无需关心这些细节,可以像调用本地方法一样即可完成远程服务调用。

自己实现 dubbo RPC(基于netty)

需求说明:

  • dubbo底层使用了netty作为网络通信框架,要求用netty实现一个简单的RPC框架
  • 模仿dubbo,消费者和提供者约定接口和协议,消费者远程调用提供者的服务,提供者返回一个字符串,消费者打印提供者返回的数据

设计说明:

  • 创建一个接口,定义抽象方法,用于消费者和提供者之间的约定。
  • 创建一个提供者,该类需要监听消费者请求,并按照约定返回数据。
  • 创建一个消费者,该类需要透明的调用自己不存在的方法,内部需要使用netty请求提供者返回数据。
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

netty学习记录 展开 收起
Java
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/LHDAXIE/netty.git
git@gitee.com:LHDAXIE/netty.git
LHDAXIE
netty
netty
master

搜索帮助