Netty 系列二(传输).
一、前言
上一篇文章我们提到 Netty 的核心组件是 Channel、回调、Future、ChannelHandler、EventLoop,这篇文章主要是对 Channel (Netty传入和传出数据的载体)做一些详细的讲解,以及介绍下 Netty 内置的传输类型。
二、传输的核心
传输 API 的核心是 interface Channel ,她被用于所有的 I/O 操作。Channel 类的层次结构如图所示:

如图,每个Channel 都会被分配一个 ChannelPipeline 和 ChannelConfig,ChannelConfig 包含了该 Channel 的所有配置设置,并且支持热更新。ChannelPipeline 是 ChannelHandler链的容器,持有所有入站和出站数据以及ChannelHandler 实例。
由于 Channel 是独一无二的,所以为了保证顺序将 Channel 声明为java.lang.Compareable的一个子接口,因此每个Channel都有不同的散列码,否则会报Error。
Netty的 Channel 实现是线程安全的,因此你可以存储一个Channel的引用,并且每当你需要向远程节点写数据时,都可以使用它,即使当时许多线程都在使用它。
Channel 的其他方法如下:

tips:
1、ChannelHandler 的典型用途:
-- 将数据从一种格式转换为另一种格式。
-- 提供异常的通知。
-- 提供Channel 变为活动的或者非活动的通知。
-- 提供当Channel 注册到 EventLoop 或者 从 EventLoop 注销时的通知。
-- 提供有关用户自定义事件的通知。
2、Netty 所提供的广泛功能只依赖于少量的接口。这意味着,你可以对你的应用程序逻辑进行重大的修改,而无需大规模的重构你的代码库。
三、Netty 内置的传输类型
Netty 内置了一些可开箱即用的传输。因为并不是它们所有的传输都支持每一种协议,所以你必须选择一个和你的应用程序所使用的协议都相容的传输。
|
名称 |
包 |
描述 |
应用场景 |
|
NIO |
io.netty.channel.socket.nio |
使用java.nio.channels 包作为基础——基于选择器的方式 |
非阻塞I/O使用 |
|
Epoll |
io.netty.channel.epoll |
由 JNI 驱动的 epoll()和非阻塞 IO。 这个传输支持只有在 Linux上可用的多种特性,如SO_REUSEPORT,比 NIO 传输更快, 而且是完全非阻塞的 |
Linux上的非阻塞 I/O 使用 |
|
OIO |
io.netty.channel.socket.oio |
使用 java.net 包作为基础——使用阻塞流 |
阻塞 I/O 使用 |
|
Local |
io.netty.channel.local |
可以在 VM 内部通过管道进行通信的本地传输 |
客户端和服务端都使用同个JVM通信 |
|
Embedded |
io.netty.channel.embedded |
Embedded 传输,允许使用 ChannelHandler 而又不需要一个真正的基于网络的传输。这在测试你的ChannelHandler 实现时非常有用 |
测试 ChannelHandler 的实现 |
1、NIO — 非阻塞I/O
Java NIO 提供了一个所有I/O操作的全异步实现。其中,选择器的背后实际上是充当了一个注册表,如图展示了该处理流程:

对于所有Netty的传输实现都共有的用户级别API完全隐藏了Java NIO的实现细节,如上一篇展示的Demo一样,Netty 这样使用Java NIO:

2、Epoll—用于 Linux 的本地非阻塞传输
Netty为Linux提供了一组NIO API, 其以一种和它本身的设计更加一致的方式使用epoll,并且以一种更加轻量的方式使用中断。 如果你的应用程序旨在运行于Linux系统, 那么请考虑利用这个版本的传输;你将发现在高负载下它的性能要优于JDK的NIO实现。
Netty 在代码中支持 Epoll 也非常简单,只需做如下的转改变:

3、OIO—旧的阻塞 I/O
Netty是如何能够使用和用于异步传输相同的API来支持OIO的呢?
上文提到,在NIO中,一个 EventLoop 对应一个线程,一个Channel 绑定一个 EventLoop,而一个EventLoop 可以绑定多个Channel 来实现异步,也就是说一个线程可以处理多个 Channel。而OIO中,一个 EventLoop 仅绑定一个 Channel,也就是说每个线程只处理一个Channel ,这就有点像传统IO中,在服务端(ServerSocket)写了一个多线程来处理客户端的并发请求。
现在还有一个问题,channel是双向的,既可以读,也可以写。而stream是单向的,OIO中利用 InputStream 来读,OutputStream 来写。那么Channel 是如何实现阻塞的读和写的呢?答案就是, Netty利用了SO_TIMEOUT这个Socket标志,它指定了等待一个I/O操作完成的最大毫秒数,I/O 操作期间Channel是阻塞的,如果操作在指定的时间间隔内没有完成,则将会抛出一个SocketTimeout Exception。 Netty将捕获这个异常并继续处理循环。在EventLoop下一次运行时,它将再次尝试。这实际上也是类似于Netty这样的异步框架能够支持OIO的唯一方式。
Netty 在代码中支持 OIO,也和NIO类似:

tips:
我从硬盘读取数据,然后程序一直等,数据读完后,继续操作。这种方式是最简单的,叫 阻塞IO。
我从硬盘读取数据,然后程序继续向下执行,等数据读取完后,通知当前程序(对硬件来说叫中断,对程序来说叫回调),然后此程序可以立即处理数据,也可以执行完当前操作在读取数据。叫 非阻塞IO。
4、Local —— 用于 JVM 内部通信的 Local 传输
Netty 提供了一个Local传输, 用于在同一个 JVM 中运行的客户端和服务器程序之间的异步通信。
在这个传输中,和服务器 Channel 相关联的 SocketAddress 并没有绑定物理网络地址;相反,只要服务器还在运行, 它就会被存储在注册表里,并在 Channel 关闭时注销。 因为这个传输并不接受真正的网络流量,所以它并不能够和其他传输实现进行互操作。因此,客户端希望连接到(在同一个 JVM 中)使用了这个传输的服务器端时也必须使用它。
服务端代码:
public void server() throws InterruptedException {
final EchoServerHandler serverHandler = new EchoServerHandler();
EventLoopGroup group = new DefaultEventLoop();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(group, group)
.channel(LocalServerChannel.class)
.childHandler(new ChannelInitializer<LocalChannel>() {
@Override
protected void initChannel(LocalChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(serverHandler);
}
});
ChannelFuture channelFuture = bootstrap.bind(new LocalAddress("foo")).sync();
System.out.println(EchoServer.class.getName() + "--started and listening for connections on--" + channelFuture.channel().localAddress());
channelFuture.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
客户端代码:
public void client() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(LocalChannel.class)
.handler(new ChannelInitializer<LocalChannel>() {
@Override
protected void initChannel(LocalChannel ch) throws Exception {
ch.pipeline().addLast(new EchoClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect(new LocalAddress("foo")).sync();
channelFuture.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
备注:现在客户端和服务端的连接一直报一个异常,查了很多资料,也看了 Github 上的诸多demo,仍然没有解决。有没有大神帮我解答下?
5、Embedded
Netty 提供了一种额外的传输, 使得你可以将一组 ChannelHandler 作为帮助器类嵌入到其他的 ChannelHandler 内部。 通过这种方式,你将可以扩展一个 ChannelHandler 的功能,而又不需要修改其内部代码。
Embedded 传输的关键是一个被称为 EmbeddedChannel 的具体的Channel实现。
如果你想要为自己的 ChannelHandler 实现编写单元测试, 那么请考虑使用 Embedded 传输。
参考资料:《Netty IN ACTION》
演示源代码:https://github.com/JMCuixy/NettyDemo
Netty 系列二(传输).的更多相关文章
- netty系列之:在netty中使用native传输协议
目录 简介 native传输协议的依赖 netty本地传输协议的使用 总结 简介 对于IO来说,除了传统的block IO,使用最多的就是NIO了,通常我们在netty程序中最常用到的就是NIO,比如 ...
- Netty系列(四)TCP拆包和粘包
Netty系列(四)TCP拆包和粘包 一.拆包和粘包问题 (1) 一个小的Socket Buffer问题 在基于流的传输里比如 TCP/IP,接收到的数据会先被存储到一个 socket 接收缓冲里.不 ...
- Netty 系列(三)Netty 入门
Netty 系列(三)Netty 入门 Netty 是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更多请参考:Netty Github 和 Netty中文 ...
- 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?
[读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...
- Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化
Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...
- Netty 系列之 Netty 高性能之道
1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用 Netty4 + Thrift 压缩二进制编解码技术,他们实现了 10 W TPS(1 K 的复杂 POJO 对象)的跨 ...
- Netty系列之Netty高性能之道
转载自http://www.infoq.com/cn/articles/netty-high-performance 1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Ne ...
- 转:Netty系列之Netty高性能之道
1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用 ...
- Wireshark入门与进阶系列(二)
摘自http://blog.csdn.net/howeverpf/article/details/40743705 Wireshark入门与进阶系列(二) “君子生非异也,善假于物也”---荀子 本文 ...
随机推荐
- 【javascript】谈谈HTML5: Web-Worker、canvas、indexedDB、拖拽事件
前言:作为一名Web开发者,可能你并没有对这个“H5”这个字眼投入太多的关注,但实际上它早已不知不觉进入到你的开发中,并且总有一天会让你不得不正视它,了解它并运用它 打个比方:<海贼王> ...
- Akka-CQRS(3)- 再想多点,全面点
上篇我介绍了CQRS模式存写部分的具体实现和akka-persistence一些函数和消息的用法.在这篇本来是准备直接用一个具体的例子来示范CQRS模式编程,主要是写端,或者是数据采集端.想着模拟收银 ...
- 【渗透技术】渗透测试技术分析_TomCat
[渗透技术]渗透测试技术分析_TomCat 本文转自:i春秋论坛 渗透测试-中间人攻击(原理)说起“中间人攻击”我想大多数对渗透测试又了解的朋友都多少有所了解,因为我们用到的次数真是非常的多.它可以将 ...
- post上传和压缩、插件模拟请求
gzip gzip一种压缩方式,或者是文件形式,它主要用于网络传输数据的压缩 gzip压缩好不好用 浏览器:网速一定.内容越小.请求响应的速度是不是更快 手机server:返回数据类型是json/ ...
- Kubernetes集群搭建之系统初始化配置篇
Kubernetes的几种部署方式 1. minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环境 ...
- 阿里妈妈前端团队出品的开源接口管理工具RAP第二代 http://rap2.taobao.org
RAP2-DELOS 开源社区版本 (后端API服务器) 项目地址:https://github.com/thx/rap2-delos RAP2是在RAP1基础上重做的新项目,它包含两个组件(对应两个 ...
- app 性能
Android App优化之性能分析工具 https://www.jianshu.com/p/da2a4bfcba68 -------------- 系列文: 背景:Android App优化, 要怎 ...
- 微信小程序:防止多次点击跳转(函数节流)和防止表单组件输入内容多次验证(函数防抖)
一.函数节流(throttle) **函数节流:一个函数执行一次后,只有大于设定的执行周期后才会执行第二次**.有个需要频繁触发函数,出于优化性能角度,在规定时间内,只让函数触发的第一次生效,后面不生 ...
- vue的router-link传参问题
一般来说,可以通过查询字符串的方式将参数传过去,方法如下: <router-link :to="{path:'/Detail', query:{ name: id }}"&g ...
- WebAssembly是解决JavaScript 痼疾的银弹?
写在前面 <没有银弹>是 Fred Brooks 在 1987 年所发表的一篇关于软件工程的经典论文.该论文的主要论点是,没有任何一项技术或方法可以能让软件工程的生产力在十年内提高十倍. ...