Transport API的核心:
Channel接口
类图表示Channel含有Pipeline和Config接口,pipeline上一节有所介绍。
Channel是线程安全的,这表示在多线环境下操作同一个Channel,不会有数据问题。
final Channel channel = null;
final ByteBuf buf = Unpooled.copiedBuffer("your data",
CharsetUtil.UTF_8); // #1
Runnable writer = new Runnable() { // #2
@Override
public void run() {
channel.write(buf.duplicate());
}
};
Executor executor = Executors.newCachedThreadPool(); // #3
// write in one thread
executor.execute(writer); // #4
// write in another thread
executor.execute(writer); // #5
#1 Create ByteBuf that holds data to write
#2 Create Runnable which writes data to channel
#3 Obtain reference to the Executor which uses threads to execute tasks
#4 Hand over write task to executor for execution in thread
#5 Hand over another write task to executor for execution in thread
This method guarantees that the messages are written in the same order as you passed them to the write method.(这个方法保证信息被写入到Channel中的顺序和调用write方法的顺序是一致的。)
Transports:
每个传输方式都有对应的EventLoop:
最后一个ThreadPerChannelEventLoop就是OIO(Old-IO)的事件监听器。
NIO – Nonblocking I/O:
The NIO transport is currently the most used. It provides a full asynchronous implementation of all I/O operations by using the selector-based approach that’s included in Java since Java 1.4 and the NIO subsystem.(NIO传输方式是用的最广泛的,通过基于Selector方式,它提供了一种全异步执行IO操作的实现。)
Real No-Blocking(很重要的一段话):
One feature that offers only the NIO transport at the moment is called “zero-file-copy”. This feature allows you to quickly and efficiently transfer content from your file system. The feature provides a way to transfer the bytes from the file system to the networkstack without copying the bytes from the kernel space to the user space. Be aware that not all operation systems support this. Please refer to operating system’s documentation to find out if it’s supported. Also, be aware that you’ll only be able to benefit from this if you don’t use any encryption/compression of the data. Otherwise it will need to copy the bytes first to the user space to do the actual work, so only transferring the raw content of a file makes use of this feature. What actually would work is to „pre-encrypt“ a file before transfer it.One application that can really make use of this is an FTP or HTTP server that downloads big files.The next transport I’ll discuss is the OIO transport, which provides a blocking transport.
大概意思:“zero-file-copy”是仅仅提供给NIO传输方式使用的特性。这个特性允许你以很快并且高效的方式从文件系统之中来传输内容。这个特性把本地文件中的字节内容可以不通过从内核空间复制到用户空间的情况下通过网络传输出去。请注意并不是所有的操作系统支持这一特性。请参考具体的操作系统文档来查看这个特性的实现情况。同样请注意如果要使用这一特性,请不要把源数据进行任何的编解码操作。否则的话会把源数据从内核空间复制到用户空间里去做编解码操作,所以只有发送源数据才会用到这一特性。更实际点的就是把源数据事先以加密的形式保存。基于FTP或者HTTP服务的用于下载大文件的应用程序可以从这个特性中获益。
OIO – Old blocking I/O:
The OIO transport is a compromise in Netty. It builds on the known unified API but isn’t asynchronous by nature because it uses the blocking java.net implementations under the hood.At first glance, this transport may not look useful to you, but it has its use cases.
When using these classes, you usually have one thread that handles the acceptance of new sockets (server-side) and then creates a new thread for each accepted connection to serve the traffic over the socket. This is needed as every I/O operation on the socket may block at any time.
If you share the same thread over more than one connection (socket), this could lead to a situation where blocking an operation could block all other sockets from doing their work.
Knowing that operations may block, you may start to wonder how Netty uses it while still providing the same way of building APIs. Here Netty makes use of the SO_TIMEOUT that you can set on a socket. This timeout specifies the maximum number of milliseconds to wait for an I/O operation to complete. If the operation doesn’t complete within the specified timeout, a SocketTimeoutException is thrown. Netty catches this SocketTimeoutException and moves on with its work. Then on the next EventLoop run, it tries again. Unfortunately, this is the only way to do this and still confirm the inner working of Netty. The problem with this approach is that firing the SocketTimeoutException isn’t free, as it needs to fill the StrackTrace, and so on.
Local – In VM transport :
Netty contains the so-called local transport. This transport implementation can be used to communicate within a VM and still use the same API you’re used to. The transport is fully asynchronous as NIO .
Embedded transport:
Netty also includes the embedded transport. This isn’t a real transport when you compare it with the others listed previously, but it’s included to complete this section. If it’s not a real transport, what can it be used for? The embedded transport allows you to interact with your different ChannelHandler implementation more easily. It’s also easy to embed ChannelHandler instances in other ChannelHandlers and use them like a helper class.This is often used in test cases to test a specific ChannelHandler implementation, but can also be used to re-use some ChannelHandler in your own ChannelHandler without event extend it. For this purpose, it comes with a concrete Channel implementation.