Transport & Buffer
Transport
传输API的核心是Channel接口,用于所有的出站操作。
每个Channel都会分配一个ChannelPipeline和ChannelConfig。ChannelConfig负责设置并存储设置,并允许在运行期间更新它们。ChannelPipeline容纳了使用的ChannelHandler实例,这些ChannelHandler将处理通道传递的“入站”和“出站”数据、ChannelHandler允许你改变数据状态和传输数据。
ChannelHandler处理以下事情
传输数据时,将数据从一种格式转换到另一种格式
异常通知
Channel变为有效或无效时通知
Channel被注册或从EventLoop中注销时获得通知
通知用户特定事件
ChannelHandler实例添加到ChannelPipeline中,在ChannelPipeline中按顺序逐条执行。它类似于一个链条。
ChannelPipeline实现了拦截过滤器模式,这意味着我们连接不通的ChannelHandler来拦截并处理经过ChannelPipeline的数据或事件。
Channel提供如下方法
eventLoop():返回分配给Channel的EventLoop
pipeline():返回分配给Channel的ChannelPipeline
isActive():返回Channel是否已经激活,已激活说明与远程连接对接
localAddress():返回已绑定的本地SocketAddress
remoteAddress():返回已绑定的远程的SocketAddress
write():写数据到远程客户端,数据通过ChannelPipeline传输过去
Channel是线程安全的,他可以被多个不同的线程安全的操作。
Netty中的传输方式有如下4种:
NIO, io.netty.channel.socket.nio —— 基于java.nio.channels工具包。使用选择器作为基础的方法。在高连接数时使用
OIO, io.netty.channel.socket.oio —— 基于java.net工具包,使用阻塞流。在低连接数,需要低延迟时,阻塞时使用
Local,io.netty,channel.local —— 用于在虚拟机间进行本地通信。在同一个JVM内通信使用
Embedded,io.netty.channel.embedded,嵌入传输 —— 允许在没有真正网络的运输中使用ChannelHandler,可以用来测试ChannelHandler的实现。测试ChannelHandler时使用
NIO
NIO通过使用选择器提供了完全异步地方式操作所有的IO。
通道状态一般有4种:一个新的Channel被接受并已准备好;Channel连接完成;Channel中有数据并已准备好读取;Channel发送数据出去。
我们可以注册一个通道或获得某个通道的改变的状态,处理完改变的状态后需要重新设置他们的状态,用一个线程来检查是否有已准备好的Channel,若有则执行相关状态。
选择器所支持的操作在SelectionKey中定义:
OP_ACCEPT:有新连接时得到通知
OP_CONNECT:连接完成后得到通知
OP_READ:准备好读取数据时得到通知
OP_WRITE:写入数据到通道时得到通知
NIO在处理过程中有一定的延迟,若连接数不大,延迟一般在毫秒级。Netty中的NIO传输是“zero-file-copy”。
Netty本地传输,这个传输实现使用相同的API用于虚拟机之间的通信,传输是完全异步地。每个Channel使用唯一的SocketAddress,客户端通过使用SocketAddress进行连接,在吴福气会被注册为长期运行,一旦通道关闭,它会自动注销。本地传输只能在本地的服务器和客户端上使用它们。Local未绑定任何的Socket,值提供JVM进程间的通信。
Netty嵌入传输,这个传输允许使用不同的ChannelHandler之间交互。
Buffer
Netty的缓冲API有两个接口:ByteBuf和ByteBufHolder。
Netty缓冲提供了以下优势:可以自定义缓冲类型;通过一个内置的复合缓冲类型实现零拷贝;扩张性好;不需要调用flip()来切换读/写模式;读取和写入索引分开;方法链;引用计数和Pooling(池)
ByteBuf
写入数据到ByteBuf后,写入索引是增加的字节数量。开始读字节后,读取索引增加,知道写入索引和读取索引处理相同的位置,若继续读,则抛出IndexOutOfBoundsException。调用ByteBuf的任何方法开始读/写都会单独维护读索引和写索引。ByteBuf的默认最大容量限制是Integer.MAX_VALUE,写入时若超出这个值将会导致一个异常。
Netty有3种类型的ByteBuf:Heap Buffer,Direct Buffer和Composite Buffer。
最常用的类型是ByteBuf将数据存储在JVM的堆空间,这是通过将数据存储在数组实现的。对缓冲区可以快速分配,当不使用时也可以快速释放。还提供了直接访问数据的方法,通过ByteBuf.array()来获取byte[]数据。访问非堆缓冲区ByteBuf的数组会导致UnsupportedOperationException,可以使用gByteBuf.hasArray()来检查是否支持访问数组。
直接缓冲区在堆之外直接分配内存。直接缓冲区不会占用堆空间容量,使用时应该考虑到应用程序要使用的最大内存容量以及如何限制它。直接缓冲区在使用Socket传递数据时性能很好,若使间接缓冲区,JVM会先将数据复制到直接缓冲区再进行传递。但直接缓冲区的缺点是在分配内存空间和释放内存时比堆缓冲区复杂。Netty使用内存池解决这个问题。直接缓冲区不支持数组访问数据。
ByteBuf directBuf = Unpooled.directBuffer(16);
if(!directBuf.hasArray){
int len = directBuf.readableBytes();
byte[] arr = new byte[len];
directBuf.getBytes(0, arr);
}
复合缓冲区使我们可以创建多个不同的ByteBuf,然后提供一个ByteBuf组合的视图。复合缓冲区就像一个列表,可以动态添加和删除其中的ByteBuf。
CompositeByteBuf comBuf = Unpooled.compositeBuffer();
ByteBuf heapBuf = Unpooled.buffer(8);
ByteBuf directBuf = Unpooled.directBuffer(16);
comBuf.addComponents(heapBuf, directBuf);
comBuf.removeComponent(0);
Iterator<ByteBuf> iter = comBuf.iterator();
while(iter.hasNext())
System.out.println(iter.nex().toString()); if(!comBuf.hasArray()){
int len = comBuf.readableBytes();
byte[] arr = new byte[len];
comBuf.getBytes(0, arr);
}
ByteBuf使用zero-based-indexing(从0开始的索引),第一个字节的索引是0,最后一个字节的索引是ByteBuf的capacity-1。
ByteBuf buf = Unpooled.buffer(16);
for(int i = 0; i < buf.capacity(); i ++){
byf.writeByte(i+1);
}
// 通过索引访问时不会推进读索引和写索引
for(int i = 0; i < buf.capacity(); i++){
System.out.println(buf.getByte(i));
}
ByteBuf提供两个指针变量支持读和写操作。读操作使用readIndex(),写操作使用writeIndex()。可以使用ByteBuf.discardReadBytes()来回收已经读取过的字节。discardReadBytes()将丢弃从索引0到readerIndex之间的字节。ByteBuf.discardReadBytes()可以用来清空ByteBuf中已读取的数据,从而使ByteBuf有多余的空间容纳新数据。但是discardReadBytes()涉及内存复制,会影响性能,一般在需要马上释放内存的时候使用收益会比较大。
任何读操作会增加readerIndex,若读取操作的参数也是一个ByteBuf而没有指定目的索引。指定的目的缓冲区的writeIndex会一直增加。新分配,包装,复制的缓冲区的readerIndex的默认值都是0。
任何写操作会增加writeIndex。若写操作的参数也是一个ByteBuf并没有指定数据源索引,那么指定缓冲区的readerIndex也会一起增加。若没有足够的可写字节会抛出IndexOutOfBoundException。
调用ByteBuf.clear()可以设置readerIndex和writeIndex为0.clear不会清楚缓冲区的内容,只是将两个索引值设置为0。
ByteBufProcessor可以实现搜索。
每个ByteBuf有两个标注索引,一个存储readerIndex,一个存储writerIndex。可以通过调用readerIndex(int readerIndex)和writeIndex(int writerIndex)移动读索引和写索引到指定位置,调用这两个方法设置指定索引位置时可抛出IndexOutOfBoundException。
调用duplicate(),slice(),slice(int index, int length),order(ByteOrder endianness)会创建一个现有缓冲区的视图。衍生的缓冲区有独立的readerIndex,writeIndex和标注索引。若需要现有缓冲区的副本,可以使用copy()或copy(int index, int length)获得。
ByteBufHolder
ByteBufHolder是一个辅助类,是一个接口,其实现类是DefaultByteBufHolder。ByteBufHolder的作用是方便访问ByteBuf中的数据,当缓冲区没用了之后,可以用ByteBufHolder释放资源。若想实现一个“消息对象”有效负载在ByteBuf,可以使用ByteBufHolder。
ByteBufAllocator
ByteBufAllocatior负责分配ByteBuf实例。ByteBufAllocator提供了各种分配不同ByteBuf方法。如ByteBufAllocator.heapBuffer();ByteBufAllocator.directBuffer();ByteBufAllocation.compositeBuffer();Netty有两种不同的ByteBufAllocator实现,一个实现ByteBuf实例池将分配和回收成本以及内存使用降低到最低;另一种实现是每次使用都创建一个新的ByteBuf实例。Netty默认使用PooledByteBufAllocator。可以通过ChannelConfig或引动设置一个不同的实现。
ServerBootstrap b = new ServerBootstrap();
EventLoopGroup group = new EventLoopGroup();
b.group(group).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>()){
proctectd void initChannel(SocketChannel ch) throws Exception{
ByteBufAllocator alloc0 = ch.alloc();
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
public void channelActive(ChannelHandlerContext ctx) throws Exception{
ByteBufAllocator alloc1 = ctx.alloc();
ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOST);
}
});
}
});
Transport & Buffer的更多相关文章
- 使用zeebe DebugHttpExporter 查看zeebe 工作流信息
zeebe 提供了一个DebugHttpExporter 可以方便的查看部署以及wokrflow 运行信息 以下是一个简单的运行试用,同时集成了prometheus,添加了一个简单的grafana d ...
- socket-详细分析No buffer space available
关键词:socket,tcp三次握手,tcp四次握手,2MSL最大报文生存时间,LVS,负载均衡 新年上班第一天,突然遇到一个socket连接No buffer space available的问题, ...
- [Network]Transport Layer
1 Principles behind Transport Layer Services 1.1 Multiplexing/Demultiplexing Multiplexing at sender ...
- socket-详细分析No buffer space available(转)
新年上班第一天,突然遇到一个socket连接No buffer space available的问题,导致接口大面积调用(webservice,httpclient)失败的问题,重启服务器后又恢复了正 ...
- ActiveMQ in Action(2) - Transport
关键字: activemq 2.2 Transport ActiveMQ目前支持的transport有:VM Transport.TCP Transport.SSL Transport.Peer ...
- org.elasticsearch.transport.ReceiveTimeoutTransportException[cluster:monitor/nodes/liveness] request_id [31] timed out after [5000ms]
ES连接超时,异常信息 2017-09-07 10:42:45.042 [elasticsearch[Bantam][transport_client_worker][T#17]{New I/O wo ...
- Kestrel.Transport.Sockets分析与使用
相信大家都清楚asp core有着非常出色的性能,它出色的性能也源于网络服务模块Kestrel:在techempower测试中Kestrel基础核心达到了700万级别的RPS吞吐能力,具备这样的能力那 ...
- HttpClient exception:ExceptionType:System.Threading.Tasks.TaskCanceledException: The operation was canceled. ---> System.IO.IOException: Unable to read data from the transport connection: Operation ca
error msg: System.Threading.Tasks.TaskCanceledException: The operation was canceled. ---> System. ...
- java socket / No buffer space available
s https://www.cnblogs.com/yiwangzhibujian/p/7107785.html Socket用在哪呢,主要用在进程间,网络间通信. https://www.cnblo ...
随机推荐
- 局域网两台机器ping超时
在防火墙的高级设置中的入站规则里,找icmpv4 ,我的两条电脑都是无线连的,看你的无线是专用还是公用,开启对应的规则. windows默认是关闭的,我的系统前些天刚重置过,ping超时,还是要手动开 ...
- 在MongoDB中执行查询、创建索引
1. MongoDB中数据查询的方法 (1)find函数的使用: (2)条件操作符: (3)distinct找出给定键所有不同的值: (4)group分组: (5)游标: (6)存储过程. 文档查找 ...
- sudo配置教程
一.相关说明 1.sudo配置文件是/etc/sudoers:另外会自动包含/etc/sudoers.d目录下的文件(/etc/sudoers文件最后有一句“#includedir /etc/sudo ...
- ssh和ssl的联系和区别
ssh:Secure Shell,安全Shell,是一个软件,处于应用层旨在取代明文通信的telnet:对应的开源实现程序是openssh. ssl:Secure Sockets Layer,安全套接 ...
- 使用Swagger2构建强大的RESTful API文档(1)(二十二)
由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这 ...
- ajax常见的面试问题
1:什么是ajax?ajax作用是什么? 异步的javascript和xml AJAX 是一种用于创建快速动态网页的技术. ajax用来与后台交互 2:原生js ajax请求有几个步骤?分别是什么 / ...
- vs2015如何使用附加进程调试发布在IIS上项目
1.如何使用附加进程调试IIS上的网站项目 1)在IIS部署一个网站项目 2)保证浏览器可访问(比如访问登陆页面) 3)在项目中LoginController断点,并在工具栏的调试找到附加到进程 4) ...
- Mysql 在 Windows环境下安装:应用程序无法正常启动0xc000007b
DirectX 修复工具 v3.7增强版 链接: https://pan.baidu.com/s/135pZUNwpXcMZjyLB41sQCg 密码: gtb5
- c语言亲缘线程通过管道通信一些疑问
亲缘线程在使用管道时,发现第一次使用管道进行进行通信完全正常(./a.out 1),但当重新运行并使用新管道文件时候出现数据无法读取的问题(./a.out 2)(./a.out 3),甚至出现子线程部 ...
- 通过改变unity中物体的alpha值实现若隐若现的效果
RawImage logo = mainLogo.transform.FindChild("back/headBack/Logo").GetComponent<RawImag ...