本文来说下有关Transport(传输) 详解

文章目录

  • 概述
  • 传输 API — Channel
    • 概述
    • 直观感受 Netty 统一的传输 API
  • Netty自带的传输方式/协议
  • 零拷贝
    • 什么是零拷贝
    • 如何实现零拷贝
      • 内存映射 Memory Mapped
      • 文件传输 Send File
  • 本文小结

概述

在网络中传递的数据总是具有相同的类型:字节。 这些字节流动的细节取决于网络传输,它是一个帮我们抽象底层数据传输机制的概念,我们不需要关心字节流动的细节,只需要确保字节被可靠的接收和发送。

当我们使用 Java 网络编程时,可能会接触到多种不同的网络 IO 模型,如 NIO,BIO (OIO: Old IO),AIO 等,我们可能因为使用这些不同的 API 而遇到问题。 Netty 则为这些不同的 IO 模型实现了一个通用的 API,我们使用这个通用的 API 比直接使用 JDK 提供的 API 要简单的多,且避免了由于使用不同 API 而带来的问题,大大提高了代码的可读性。 在传输这一部分,我们将主要学习这个通用的 API,以及它与 JDK 之间的对比。


传输 API — Channel

概述

传输 API 的核心是 Channel 接口 (io.netty.Channel,而非 java nio 的 Channel) ,它被用于所有的 IO 操作

Channel 结构层次:

每个Channel都会被分配一个ChannelPipeline和ChannelConfig:

  • ChannelConfig包含了该Channel的所有配置,并允许在运行期间更新它们。
  • ChannelPipeline 存储了所有用于处理出站和入站数据的 ChannelHandler, 我们可以在运行时根据自己的需求添加或删除ChannelPipeline中的ChannelHandler。

此外,Channel 还有以下方法值得留意:

方法名 描述
eventLoop 返回当前Channel注册到的EventLoop
pipeline 返回分配给Channel的ChannelPipeline
isActive 判断当前Channel是活动的,如果是则返回true。 此处活动的意义依赖于底层的传输,如果底层传输是TCP Socket,那么客户端与服务端保持连接便是活动的;如果底层传输是UDP Datagram,那么Datagram传输被打开就是活动的。
localAddress 返回本地SocketAddress
remoteAddress 返回远程的SocketAddress
write 将数据写入远程主机,数据将会通过ChannelPipeline传输
flush 将之前写入的数据刷新到底层传输
writeFlush 等同于调用 write 写入数据后再调用 flush 刷新数据

举个例子:写数据到远程已连接客户端可以调用 Channel.write() 方法,如下代码:

Channel channel = ....; // 获取 channel 的引用
// 创建 ByteBuf 保存写的数据
ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8);
// 写数据,并刷新
ChannelFuture cf = channel.writeAndFlush(buf);// 添加 ChannelFutureListener 监听,即可在写操作完成后收到通知,
cf.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) {if (future.isSuccess()) { // 写操作顺利完成System.out.println("Write successful");} else { // 写操作完成时出现错误System.err.println("Write error"); future.cause().printStackTrace();}}
});

Channel 是线程安全(thread-safe)的,它可以被多个不同的线程安全的操作,在多线程环境下,所有的方法都是安全的。正因为 Channel 是安全的,我们存储对Channel的引用,并在学习的时候使用它写入数据到远程已连接的客户端,使用多线程也是如此。下面的代码是一个简单的多线程例子:

final Channel channel = ...; // 获取channel的引用
// 创建一个 ByteBuf 保存写的数据
final ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8).retain();
// 创建 Runnable 用于写数据到 channel
Runnable writer = new Runnable() { @Overridepublic void run() {channel.writeAndFlush(buf.duplicate());}
};
// 获取 Executor 的引用使用线程来执行任务
Executor executor = Executors.newCachedThreadPool();// 写进一个线程
executor.execute(writer);//写进另外一个线程
executor.execute(writer);

直观感受 Netty 统一的传输 API

Netty 使用相同的 API 来实现每个传输,它并不关心你使用什么来实现。Netty 通过操作接口 Channel 、ChannelPipeline 和 ChannelHandler来实现。下面我们通过直观的例子来感受下,Netty 只需要简单的修改就可以将 BIO 改为 NIO

Ⅰ Netty BIO 版本

下面代码是使用 Netty 作为网络框架编写的一个阻塞 IO 例子:

public class NettyOioServer {public void server(int port) throws Exception {final ByteBuf buf = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8")));EventLoopGroup group = new OioEventLoopGroup();try {// 创建一个引导类 ServerBootstrapServerBootstrap b = new ServerBootstrap();b.group(group)// 使用 OioEventLoopGroup 允许阻塞模式(Old-IO 即 BIO).channel(OioServerSocketChannel.class) .localAddress(new InetSocketAddress(port))// 指定 ChannelInitializer 将给每个接受的连接调用.childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {// 添加 ChannelHandler 拦截事件,并允许他们作出反应ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception{// 写信息到客户端,并添加监听:一旦消息写入就关闭连接ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);}});}});// 绑定服务器来接受连接ChannelFuture f = b.bind().sync();f.channel().closeFuture().sync();} finally {// 释放所有资源group.shutdownGracefully().sync();}}
}

Ⅱ Netty NIO 版本

下面是 Netty NIO 的代码,

Transport(传输) 详解相关推荐

  1. Ymodem传输详解

    Ymodem传输详解 ymodem简介: YModem协议是由XModem协议演变而来的,每包数据可以达到1024字节,是一个非常高效的文件传输协议. Ymodem是一种错误纠正协议.使用较大数据块的 ...

  2. 空地通信传输详解——飞机是这样和地面通信的

    来源:电子万花筒 飞机在空中飞行时是如何与地面联络的呢?飞机在飞行中的数据如何进行空地传输呢?那些部件的数据可以被传输呢? 飞机的导航.通信.识别系统主要就是保证飞行的,保障在天上.空对空.空对地.地 ...

  3. 移动端实时音视频直播技术中推流和传输详解

    推流是直播的第一公里,直播的推流对这个直播链路影响非常大,如果推流的网络不稳定,无论我们如何做优化,观众的体验都会很糟糕.所以也是我们排查问题的第一步,如何系统地解决这类问题需要我们对相关理论有基础的 ...

  4. UDP的可靠性传输详解

    文章目录 UDP和TCP的区别 TCP UDP 为什么要使用UDP传输可靠性数据 如何使用UDP传输可靠性数据 KCP的使用方式 kcp配置模式 kcp的协议头 UDP和TCP的区别 Tcp和udp都 ...

  5. 符合SL651-2014水文规约遥测终端图片传输详解

    河流.湖泊.水库等水情监测系统中,除了常规的水位.降雨量.流量等监测,有时候需要通过图像直观的反应现场的水位水尺的变化情况,本文将具体描述如何通过水文遥测终端RTU远程控制工业照相机拍摄并回传图像. ...

  6. php json 压缩传输,详解PHP如何将返回的JSON数据用gzip压缩输出

    PHP如何将返回的JSON数据用gzip压缩输出?本文主要介绍了将PHP中返回的JSON格式数据用gzip压缩输出的方法,文中示例环境为Linux系统与Apache服务器,需要的朋友可以参考下.希望对 ...

  7. 流媒体协议之RTMP详解

    流媒体协议之RTMP详解 文章目录 流媒体协议之RTMP详解 1 RTMP概述 2 RTMP交互过程 2.1 握手协议 2.2 RTMP分块(chunk) 2.3 协议控制消息(Protocol Co ...

  8. TCP固定头部结构详解

    1.前言 尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务.TCP提供一种面向连接的.可靠的字节流服务. 使用TCP协议通信的双方必须先建立连接,然后才能开始数 ...

  9. python之ssh超级详解

    环境 操作系统及内核版本 [root@ceph01 ssh]# cat /etc/redhat-release CentOS Linux release 7.8.2003 (Core)[root@ce ...

最新文章

  1. Linux内存初始化(一)
  2. 解决 Android 中出现依赖多个版本支持库的问题
  3. 监听程序配制及数据备份
  4. web前端学习总结--JQuery
  5. linux 文件浏览器_浏览Linux文件系统
  6. MNIST的AlexNet实现
  7. 编程语言对比 数组
  8. 系统分析师资料_软考 系统分析师考试通过总结
  9. Java结合源码之究极基础复习设计模式复习
  10. 《数据整理实践指南》一第2章 是我的问题还是数据的问题
  11. 私有5g网络_面向企业的私有5G网络
  12. 【Clover】服务器环境中通过Clover boot引导黑群晖DSM(Linux)+Win系统的解决方案与常见bug排查
  13. 浅谈对于机器学习的理解
  14. 导向滤波算法原理与代码
  15. 一些常用开发软件下载地址-msdn.itellyou.cn
  16. 第14课:走向技术管理者的4种方式
  17. 移动应用如何利用社交平台获取流量
  18. xxljob从入门到精通-全网段最全解说
  19. 全球地名中英文对照表(B)
  20. 2019Java视频教程-Spring Boot实战

热门文章

  1. 从视图到控制器的传值方法(表单)
  2. Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(三)
  3. 电梯调度需求调研报告
  4. Red Gate系列之一 SQL Compare 10.4.8.87 Edition 数据库比较工具 完全破解+使用教程
  5. jquery autocomplete的使用
  6. SpringBoot如何使用拦截器
  7. MessageQueue的使用方法(二)
  8. LinkedIn 开源多媒体对象存储数据库 Ambry
  9. jdk1.8新特性之lambda表达式及在Android Studio中的使用举例
  10. __stdcall __cdecl 引起的程序崩溃