##Netty

Netty

###架构总览
archietecture

Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server. – Netty 官网

总体来说 Netty算是一个异步-事件驱动网络框架,具有很高的性能与扩展能力。

###重要组件介绍

  1. ServerBootstrap instance is then configured, as shown in the following listing, to set options, such as the port, the threading model/event loop, and the server handler to handle the business logic

  2. EventExecutor : a special EventExecutorGroup which comes with some handy methods to see if a Thread is executed in a event loop.

  3. EventExecutorGroup : responsible for providing the EventExecutor’s to use via its next() method.

2.Bootstrap

3.Channel

4.ChannelPipeline

可以理解为ChannelHandler的有序容器

5.ChannelBuffer

6.ChannelHandler

ChannelHandler分为ChannelInboundHandler与ChannelOutboundHandler两类

ChannelInboundHandler对从Client –> Server的消息进行处理

ChannelOutboundHandler对从Server –> CLient的消息进行处理

7.ChannelHandlerContext

###示例程序
以著名的Discard程序为例 说明Netty程序基本结构

首先是Server端结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new DiscardServerHandler());
}
});

// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(PORT).sync();

// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
f.channel().closeFuture().sync();

之后是Client端结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
p.addLast(new DiscardClientHandler());
}
});

AbstractBootstrap中
doBind(final SocketAddress localAddress)

init(Channel channel)

A Future is an abstraction, which represents a value that may become available at some point.

A Future object either holds the result of a computation or, in the case of a failed computation, an exception.

##Your first Netty application

A Netty application begins with one of the Bootstrap classes, a Bootstrap is a construct Netty provides that makes it easy for you to configure how Netty should setup or bootstrap the application.

In order to allow multiple protocols and various ways of processing data, Netty has what are called handlers.

The ChannelInboundHandler receives messages which you can process and decide what to do with it.

When a channel is registered, Netty binds that channel to a single EventLoop for the lifetime of that Channel. EventLoop is always bound to a single Thread that never changed during its life time.

EventLoopGroup contains one or more EventLoop

Netty allows the same EventLoopGroup to be used for processing IO and accepting
connections.

To understand what happens to data when it is written or read, it is first essential to have some understanding of what handlers are.

Handlers themselves depend upon the aforementioned ChannelPipeline to prescribe their order of execution.

A ChannelHandler may do some action on the data and then may pass it to the next
ChannelHandler in the ChannelPipeline. Another often action is do not do any action at all and just pass the specific event to the next ChannelHandler in the ChannelPipeline. This next ChannelHandler may handle it then or just forward it to the next ChannelHandler again.

Both ChannelInboundHandler and ChannelOutboundHandler can be mixed into the same ChannelPipeline.

###Encoding

When you send or receive a message with Netty it must be converted from one form to another.

If the message is being received it must be converted from bytes to a Java object (decoded by some kind of decoder).

If the message is being sent it must be converted from a
Java object to bytes (encoded by some type of encoder).

##Transports

Channel interface, which is used for all of the outbound operations. All I/O operations in Netty are asynchronous.

A channel provides a user:
Current state of the channel 
ChannelConfig configuration parameters of the channel
I/O operations that the channel supports
ChannelPipeline which handles all I/O events and requests

The ChannelPipeline holds all of the ChannelHandler instances that should be used for the inbound and outbound data that is passed through the channel.

ChannelHandler use for :

  1. Transforming data from one format to another.
  2. Notifying you of exceptions.
  3. Notifying you when a Channel becomes active or inactive.
  4. Notifying you once a channel is registered/deregistered from an EventLoop.
  5. Notifying you about user-specific events.

###IOI(Old blocking I/O )

The OIO transport is a compromise in Netty.

##Buffers

Different types of ByteBuf

  1. HEAP BUFFERS
  2. DIRECT BUFFERS
  3. COMPOSITE BUFFERS

##Transports
The heart of the transport API is the Channel interface, which is used for all of the outbound operations. A channel has a ChannelPipeline and a ChannelConfig
assigned to it.

The ChannelPipeline holds all of the ChannelHandler instances that should be used for the inbound and outbound data that is passed through the channel.

##ChannelHandler

your channel handler must extend the ChannelInboundHandlerAdapter class and override the messageReceived method. This method is called every time messages are received, which in this case are bytes.

channelActive Called after the connection to the server is established

channelRead0 Called after you receive data from the server

exceptionCaught Called if any exception was raised during processing

ChannelInboundHandler and ChannelOutboundHandler extends ChannelHandler

##ChannelPipeline

The ChannelPipeline holds all of the ChannelHandler instances that should be used for the inbound and outbound data that is passed through the channel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
                                              I/O Request
via {@link Channel} or
{@link ChannelHandlerContext}
|
+---------------------------------------------------+---------------+
| ChannelPipeline | |
| \|/ |
| +---------------------+ +-----------+----------+ |
| | Inbound Handler N | | Outbound Handler 1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler N-1 | | Outbound Handler 2 | |
| +----------+----------+ +-----------+----------+ |
| /|\ . |
| . . |
| ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
| [ method call] [method call] |
| . . |
| . \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 2 | | Outbound Handler M-1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 1 | | Outbound Handler M | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
+---------------+-----------------------------------+---------------+
| \|/
+---------------+-----------------------------------+---------------+
| | | |
| [ Socket.read() ] [ Socket.write() ] |
| |
| Netty Internal I/O Threads (Transport Implementation) |
+-------------------------------------------------------------------+

Included transports

NIO  Nonblocking I/O

OIO  Old blocking I/O

Local  In VM transport

Embedded transport

##Codec

##Bootstrap

A Netty application begins with one of the Bootstrap classes, is a construct Netty provides that makes it easy for you to configure how Netty should setup or bootstrap the application.

The ChannelInboundHandler receives messages which you can process and decide what to do with it. You may also write/flush data out from inside an ChannelInboundHandler when your application needs to provide a response.

ChannelInitializer is to add ChannelHandler implementations to whats called the ChannelPipeline.

All Netty applications are based on what is called a ChannelPipeline.

All IO operations in Netty are performed asynchronously.

ChannelFuture is a special java.util.concurrent.Future, which allos you to register ChannnelFutureListeners tot he ChannelFuture.

##Thread Model

ChannelHandlers contain your business logic, are guaranteed to be executed by a single thread at the same time for a specific Channel. This doesnt mean Netty fails to use multithreading, but it does limit each connection
to one thread as this design works well for nonblocking execution.

Theres no need for you to think about any of the issues you often have when working with multithreaded applications.


General API for compression codecs

Each compression codec is presented as its own class. It’s difficult to switch one compression codec to another without significant code modifications.

Modifications:
Added classes:

  • CompressionCodecFactory - factory for all compression codecs
  • CompressionDecoder - abstract class, parent for all compression decoders
  • CompressionEncoder - abstract class, parent for all compression encoders
  • CompressionFormat - enum with all available compression formats

Extend all compression encoders and decoders to use new abstract classes.

Result:General API for every compression codecs.


Reference :

  1. New and noteworthy in 4.0
  2. Netty4学习笔记