4.3 已包含的传输
Netty已经附带了一些您可以使用的传输方式。并非都支持所有协议,这意味着要使用的传输方式还取决于应用程序所依赖的基础协议。您将在本节中了解有关哪种传输支持哪种协议的更多信息。
表4.1显示了Netty默认包含的所有传输。
Name
Package
Description
NIO
io.netty.channel.socket.nio
Uses the java.nio.channels package as a foundation and so uses a selector-based approach.
OIO
io.netty.channel.socket.oio
Uses the java.net package as a foundation and so uses blocking streams.
Local
io.netty.channel.local
A local transport that can be used to communicate in the VM via pipes.
Embedded
io.netty.channel.embedded
Embedded transport, which allows using ChannelHandlers without a real network based Transport. This can be quite useful for testing your ChannelHandler implementations.
现在,让我们通过首先研究最常用的传输实现,即NIO传输来了解更多细节。
4.3.1 NIO - Nonblocking I/O
NIO传输当前是最常用的。它使用从Java 1.4和NIO子系统开始包含在Java中的基于选择器的方法,提供了所有I / O操作的完全异步实现。
其思想是,一旦一个频道的状态发生变化,用户可以注册以获得通知。 可能发生的变化有:
一个新的频道被接受并准备就绪。
一个通道连接完成。
通道接收到的数据已准备好读取。
频道能够在频道上发送更多的数据。
然后,实现负责对这些状态更改作出反应,以重置它们,并在状态再次更改时通知它们。这是通过检查更新的线程完成的,如果有更新,则相应地分派它们。(The implementation is then responsible for reacting to these state changes to reset them and to be notified once a state changes again. This is done with a thread that checks for updates and, if there are any, dispatches them accordingly.)
在这里,可能只对其中一个事件进行通知注册,而忽略其余的事件。
底层选择器支持的精确位集如表4.2所示。 这些都是在SelectionKey类中定义的。
Name
Description
OP_ACCEPT
Get notified once a new connection is accepted and a channel is created.
OP_CONNECT
Get notified once a connection attempt finishes.
OP_READ
Get notified once data is ready to be read out of the channel.
OP_WRITE
Get notified once its possible to write more data to the channel. Most of the time this is possible, but it may not be because the OS socket buffer is completely filled. This usually happens when you write faster then the remote peer can handle it.
Netty的NIO传输在内部使用此模型来接收和发送数据,但是向用户公开自己的API,这完全隐藏了内部实现。如前所述,这有助于只向用户公开一个统一的API,同时隐藏所有内部组件。 图4.2显示了流程。


由于这种传输的性质,它在处理事件时可能会带来一些延迟,因此吞吐量可能会比OIO传输低。这是由选择器的工作方式引起的,因为通知状态更改可能需要一些时间。我不是说延迟秒,只有毫秒。这听起来似乎没有太大的延迟,但是如果您尝试在提供千兆位速度的网络中使用网络应用程序,则可能会累加起来。
目前NIO传输仅提供的一项特性称为零文件复制。此功能使您可以快速有效地从文件系统传输内容。该功能提供了一种将字节从文件系统传输到网络堆栈的方法,而无需将字节从内核空间复制到用户空间。
请注意,并非所有操作系统都支持此功能。请参阅操作系统的文档以了解是否受支持。另外,请注意,如果不使用任何数据加密/压缩方法,您将能从中受益。否则,它将需要首先将字节复制到用户空间以进行实际工作,因此只有传输文件的原始内容才能使用此功能。实际可行的方法是在传输文件之前对文件进行预加密。
一个可以真正利用此功能的应用程序是下载大文件的FTP或HTTP服务器。
我将讨论的下一个传输是OIO传输,它提供阻塞传输。
4.3.2 OIO - Old blocking I/O
OIO传输是Netty的折衷方案。它建立在已知的统一API上,但本质上不是异步的,因为它在后台使用了阻塞的java.net实现。乍一看,这种传输对您可能看起来没有用,但有其用例。稍后您将看到几个用例,但是在本节中,我们将专门研究一个用例。
假设需要移植一些遗留的代码,它使用许多库来进行阻塞调用(例如通过jdbc进行数据库调用)。将逻辑移植到不阻塞可能是不可行的。 相反,您可以在短期内使用OIO传输,然后将其移植到纯异步传输中。 让我们把重点放在如何做有效。
因为OIO传输内部使用java.net类,所以它也使用与以前编写网络应用程序时可能已经熟悉的逻辑相同的逻辑。
使用这些类时,通常有一个线程处理新套接字的接受(服务器端),然后为每个接受的连接创建一个新线程,以通过套接字提供服务。这是必需的,因为套接字上的每个I / O操作都可能随时阻塞。如果您在一个以上的连接(套接字)上共享同一线程,则可能导致阻塞操作的情况,从而阻塞所有其他套接字的工作。
知道操作可能会阻塞,您可能会开始想知道Netty如何使用它,同时仍然提供构建API的相同方法。Netty在这里使用您可以在套接字上设置的SO_TIMEOUT。此超时指定等待I / O操作完成的最大毫秒数。如果操作未在指定的超时时间内完成,则抛出SocketTimeoutException。Netty捕获了此SocketTimeoutException并继续其工作。然后在下一次运行EventLoop时,它将再次尝试。不幸的是,这是唯一的方法,并且仍然可以确认Netty的内部工作。这种方法的问题是触发SocketTimeoutException不是无偿的,因为它需要填充StrackTrace,依此类推。
Figure 4.3 shows the logic.

1 Thread allocated to socket
2. Socket connected to remote peer
3. Read operation that may block
4. Read complete
5. Read completed and able to read bytes so handled them
6. Execute other tasks submitted belonging to socket
7. Try to read again
现在您知道了Netty中最常用的两种传输方式,但是还有其他一些,我们将在下一节中介绍。
4.3.3 Local - In VM transport
Netty包含所谓的本地运输。此传输实现可用于在VM之间进行通信,并且仍使用与以前相同的API。传输与NIO完全异步。
每个通道都使用唯一的SocketAddress,该地址存储在注册表中。然后可以使用此SocketAddress通过客户端连接到它。只要服务器正在运行,它将被注册。通道关闭后,它将自动注销它,因此客户端将无法再访问它。
连接到本地传输服务器的行为与其他传输实现几乎相同。需要注意的重要一件事是,您只能同时在服务器和客户端使用它们。无法在服务器端使用本地传输,而在客户端使用其他传输。这似乎是一个限制,但是一旦您想到它,它就会变得有意义。由于本地传输不绑定套接字,因此不接受实际的网络流量,因此无法与任何其他传输实现一起使用。
4.3.4 Embedded transport
Netty还包括嵌入式传输。 当您将它与前面列出的其他进行比较时,这并不是一个真正的传输,但它包含在本节中。 如果它不是真正的传输,它可以用来做什么?
嵌入式传输允许您更容易地与不同的ChannelHandler实现交互。 在其他Channel Handler中嵌入Channel Handler实例并使用它们也很容易的,它像一个助手类。
这通常用于测试用例来测试特定的ChannelHandler实现,但也可以用于在您自己的ChannelHandler中重用一些ChannelHandler,而不需要事件扩展它。 为了这个目的, 它附带了一个具体的通道实现。
Channel type
Usage
EmbeddedChannel
Test ChannelHandler or embedded them in your own ChannelHandler for reuse.
第10章详细介绍了嵌入式传输如何用于测试目的。
最后更新于
这有帮助吗?