netty indroduction
TRANSCRIPT
May 1, 2023 1
Netty5.0 OverviewLAURENCE HO, JAN 2016
May 1, 2023 2
AgendaWhat is Netty?
Blocking and Non-Blocking
Asynchronous
Main Components
IP Address Filter
Security Issues
Serialization via Protocol Buffers
May 1, 2023 3
What is Netty?1. non-blocking I/O (NIO) client-server framework
2. asynchronous event-driven network application framework
3. multi-protocol supporting
May 1, 2023 4
Benefits of NettyUnified API for various transport types - blocking and non-blocking socket
Highly customizable thread model - single thread, one or more thread pools such as SEDA
No additional dependencies, JDK 5 (Netty 3.x) or 6 (Netty 4.x) is enough
Better throughput, lower latency
Less resource consumption
Complete SSL/TLS and StartTLS support
May 1, 2023 5
Blocking and Non-Blocking Blocking I/O (OIO):
Socket
Read/Write
Thread
Socket
Read/Write
Thread
Socket
Read/Write
Thread
Socket
Read/Write
Thread
May 1, 2023 6
Blocking and Non-Blocking Non-blocking I/O (NIO):
Socket
Read/Write
Selector
Thread
Socket
Read/Write
Socket
Read/Write
Socket
Read/Write
May 1, 2023 7
Blocking and Non-Blocking OIO:
NIO:
BufferedReader in = new BufferedReader( InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); String request, response; while ((request = in.readLine()) != null) {
if ("Done".equals(request)) { break;
} } response = processRequest(request);out.println(response);
While(true){selector.select(); //request events from multiple channelsIterator it = selector.selectedKeys().iterator();while(it.hasNext()){
SelectorKey key = (SelectionKey) it.next();handleKey(key);it.remove();
}}
May 1, 2023 8
AsynchronousAll I/O operations do not block
Get notification when the operation completed
Be able to share threads across many connections
In os: o select()/poll(): traditional POSIX pollingo epoll(): event-based polling, on Linux 2.5.44+o kqueue: on FreeBSD, Mac OS X
Java example:Channel channel = ...;ChannelFuture future = channel.connect( new InetSocketAddress("192.168.0.1", 25));
May 1, 2023 9
Echo client & server
Client1
Client2
Client3
Hello
Hello
Hello
World
World
World
ServerConnection1
Connection2Connection3
May 1, 2023 10
Main ComponentsBootstrap and ServerBootstrap
EventLoop
Channel
ChannelFuture
ChannelPipeline
ChannelHandlers
ChannelHandlerContext
May 1, 2023 11
Bootstrapping a server
ServerBootstrap bind() ServerChannel
Channel1 Channel1 Channel1
A ServerChannel is created when bind() is called.
A new Channel is created by the ServerChannel when a connection is accepted.
May 1, 2023 12
Bootstrapping a client
Bootstrapbind()
connect()
Channel1
Channel1
Bootstrap will create a new Channel after bind() has been called, after which
connect() is called to establish the connection.
Bootstrap will create a new channel when connect() is called.
May 1, 2023 13
Bootstrapping clients from a Channel
ServerBootstrap bind() ServerChannel
Channel Bootstrap connect() Channel
EventLoop
ServerBootstrap creates a new ServerChannel when bind() is called.
ServerChannel accepts new connections and creates child channels to serve them.
Channel created for an accepted connection.
Bootstrap created by the Channel will create a new Channel when connect() is called.
May 1, 2023 14
Bootstrap, EventLoop and Channel
A Bootstrap that makes it easy to bootstrap a Channel to use for clients.
An EventLoopGroup contains one or more EventLoops.
EventLoop handles all the I/O operations for a Channel once registered.
All I/O events processed by an EventLoop are handled on its dedicated Thread.
A Channel is registered for its lifetime with a single EventLoop.
EventLoopGroup workerGroup = new NioEventLoopGroup();try { ServerBootstrap b = new ServerBootstrap(); b.group(workerGroup).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new SimpleServerHandler()); } }).option(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections. ChannelFuture f = b.bind(port).sync();
// Wait until the server socket is closed. f.channel().closeFuture().sync();} finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully();}
May 1, 2023 15
Bootstrap, EventLoop and Channel
EventLoopGroup With 3
EventLoopsEventLoop
Create Channel1 Register EventLoop with Channel
Process I/O with EventLoop during entire lifetime
Channel1
EventLoopEventLoop
EventLoop
Channel1
EventLoop
Channel1
May 1, 2023 16
The Channel LifecycleState Description
ChannelUnregistered The Channel was created, but isn’t registered to an EventLoop.
ChannelRegistered The Channel is registered to an EventLoop.
ChannelActive The Channel is active (connected to its remote peer). It’s now possible to receive and send data.
ChannelInactive The Channel isn’t connected to the remote peer.
ChannelRegistered ChannelActive
ChannelInactive ChannelUnregistered
May 1, 2023 17
ChannelFutureDo asynchronous
Its addListener() method registers a ChannelFutureListener to be notified when an operation has completed (whether or not successfully).
Example: ChannelFuture f = ctx.writeAndFlush(time);f.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { assert f == future; ctx.close(); }});
May 1, 2023 18
ChannelPipelineEvery connection(channel) is attached to a ChannelPipeline
One ChannelPipeline one connection(channel)
All events get passed through it
It contains a stack of ChannelHandlers:o Protocol: encoders & decoderso Security layers: SSL/TLS, authenticationo A custom handlero Others...
Example: ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(sslCtx.newHandler(ch.alloc()));pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());pipeline.addLast(new SimpleServerHandler()); // A custom handler
May 1, 2023 19
ChannelHandlersEverything is an event
Process message(event): reading and writing
Inbound message or outbound message
Check status or do operations
Connection established or shout down
Byte or message based
Example: public class SimpleServerHandler extends ChannelHandlerAdapter {@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { // do something }@Override public void channelActive(final ChannelHandlerContext ctx) { // do something }@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // do
something }}
May 1, 2023 20
ChannelHandlerContextan association between a ChannelHandler and a ChannelPipeline.
it is created whenever a ChannelHandler is added to a ChannelPipeline.
Channel ChannelHandler ChannelHandler ChannelHandler
ChannelHandlerContext ChannelHandlerContext ChannelHandlerContext
ChannelPipeline
Channel bound to pipeline
Pipeline bound to Channel containing
Handlers
Context created when adding Handler to Pipeline
May 1, 2023 21
IP Address FilterNetty can filter connections by IP address and subnet mask.
Example:
RuleBasedIpFilter.class: This class allows one to filter new connections based on the IpFilterRules. If no rules are provided, all connections will be accepted.
IpSubnetFilterRule.class: Use this class to create rules for RuleBasedIpFilter that group IP addresses into subnets. Supports both, IPv4 and IPv6.
ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new RuleBasedIpFilter(new IpSubnetFilterRule("192.168.20.113",32,IpFilterRuleType.REJECT)));
May 1, 2023 22
Security IssueSecuring Netty applications with SSL/TLS o Use SslHandler.class doing decryption and encryption
SslHandlerEncrypted Decrypted Inbound
PlainEncryptedOutbound
1. Encrypted inbound data is intercepted by the SslHandler
2. The SslHandler decrypts the data and directs it inbound
3. Outbound data is passed through the SslHandler
4. The SslHandler encrypts the data and passes it outbound
May 1, 2023 23
Adding SSL/TSL support(Mutual SSL Authentication)
public class SecureServerInitializer extends ChannelInitializer<SocketChannel> { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline();
String password = "password";
KeyStore ks = KeyStore.getInstance("JKS"); ks.load(ClassLoader.class.getResourceAsStream(File.separator + "netty_server.jks"), password.toCharArray());
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance("SunX509"); tmFactory.init(ks);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, password.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null);
SSLEngine sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); sslEngine.setNeedClientAuth(true);
pipeline.addFirst("SSL", new SslHandler(sslEngine));
}
Adds the SslHandler to the pipeline as the first handler
May 1, 2023 24
Set SSLEngine SSLEngine sslEngine = sslContext.createSSLEngine();sslEngine.setUseClientMode(false);sslEngine.setNeedClientAuth(true);
sslEngine.setEnabledProtocols(sslEngine.getSupportedProtocols());sslEngine.setEnabledCipherSuites(sslEngine.getSupportedCipherSuites());sslEngine.setEnableSessionCreation(true);
May 1, 2023 25
Building Netty HTTP/HTTPS applications HTTP is based on a request/response pattern: the client sends an HTTP request to the server, and the server sends back an HTTP response.
Netty provides a variety of encoders and decoders to simplify working with this protocol.
Example: public class HttpServerPipelineInitializer extends ChannelInitializer<Channel> { private final boolean client;
public HttpServerPipelineInitializer(boolean client) { this.client = client; }
@Override protected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());pipeline.addLast("encoder", new HttpResponseEncoder());pipeline.addLast("codec", new HttpServerCodec());pipeline.addLast("aggregator", new HttpObjectAggregator(512 *
1024));pipeline.addLast("compressor", new HttpContentCompressor());
}}
Adds HttpObjectAggregator with a max message size of 512 KB to the pipeline
Automatically compressing HTTP messages
May 1, 2023 26
Serialization via Protocol Buffers
public class SecureServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public SecureServerInitializer(SslContext sslCtx) { this.sslCtx = sslCtx; }
@Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline();
pipeline.addFirst(sslCtx.newHandler(ch.alloc()));
// Add protobuf pipeline.addLast(new ProtobufVarint32FrameDecoder()); pipeline.addLast(new ProtobufVarint32LengthFieldPrepender()); pipeline.addLast(new ProtobufDecoder(PROTO_JAVA_INSTANCE)); pipeline.addLast(new ProtobufEncoder());
// and then business logic. pipeline.addLast(new SecureServerHandler()); }}
Adds Protobuf-Varint32Frame- Decoder to break down frames
Adds ProtobufEncoder to handle encoding of messages
Adds ProtobufDecoder to decode messages