Reading Notes: Netty in Action

Want to know more about Java networking.

This book is recommended in a couple places, Netty looks like a good Java project to know more on Java networking. From my understanding, Netty should be similar to Apple networking layer or even similar to an iOS app. Networking layer is basically an event driven application to poll events and execute registered callbacks from the user code. The goal of finish reading this book is to build my own HTTP/RPC server and deploy in my Raspberry Pis :)

Chapter 1: Introduction to Netty

This chapter is pretty basic, it covers what is Netty, non-blocking IO & Event Driven.

Chapter 2: You First Netty Application

This chapter is like an appetizer to build a netty application (server/client combo) to motivate you to read over the whole book.

Chapter 3: Netty Components and design

Channel, EventLoop & ChannelFuture

Channel

Netty’s Channel interface provides an API that reduces the complexity of working directly with Java Socket class. Channel is root to an extensive class hierarchy with many predefined implementations.

EventLoop

EventLoop is Netty’s abstraction for handling events during lifetime of a connection.

  • An EventLoopGroup contains one more more EventLoops
  • An EventLoop is bound to a single Thread for its lifetime.
  • All IO events processed by an EventLoop are handled on its dedicated thread.
  • A Channel is registered for tis lifetime with a single EventLoop
  • A single EventLoop may be assigned to one or more Channels.

ChannelFuture

ChannelFuture can be registered with addListener(). The registered ChannelFutureListener will be notified when an operator has completed.

ChannelHandler

Serves as the container for all application logic that applies to handling in bound and outbound data.

ChannelPipeline

Provides a container for a chain of ChannelHandlers and defines and API for propagating the flow of inbound and outbound events along the chain.

You can start interacting with Netty by going through the whole ChannelPipeline (talk to Channel) or just talk to a ChannelHandler inside the pipeline so that only subsequent ChannelHandlers will be called.

Encoders and Decoders

Used for encoding and decoding network traffic.

Bootstrapping

Bootstrap class provides containers for the configuration of an application’s network layer — binding process to a port or connection a process to another one.

There are 2 types of Bootstraps. ServerBootstrap is used to bind to a port because servers must listen for connections. Bootstrap is used by client application to connect to a remote peer.

ServerBootstrap requires two EventLoopGroups. It needs two distinct sets of Channels. The first set will contain a single ServerChannel representing the server’s own listening socket, bound to a local port. The second set will contain all of the Channels that have been created to handle incoming client connections — one for each connection the server has accepted.

Chapter 4: Transports

Netty abstracts out NIO/OIO and minimal changes needed to switch from one version of Java networking IO to another version of Java networking IO package.

ChannelPipeline holds all of the ChannelHandler. Typical usages for ChannelHandlers:

  • Transform data from one format to another
  • Provide notification for exception
  • Provide notification of a Channel becoming active or inactive
  • Provide notification when a channel is registered with or deregistered from an EventLoop
  • Provide notification about user-defined events

You can modify ChannelPipeline on the fly.

Included transports

Netty comes bundled with several transports that are ready to use. However, not all of them support every protocol and you’d have to select a transport that is compatible with the protocols employed by your application.

Transport Use cases

(X means support)

Chapter 5: ByteBuf

ByteBuf is Netty’s better version of Java NIO’s ByteBuffer. Advantages:

  • Extensible to user-defined buffer types.
  • Transparent zero-copy is achieved by a built-in composite buffer type.
  • Capacity is expanded on demand (as with JDK StringBuilder)
  • Switch between reader & writer mode doesn’t require a flip() method.
  • Reading & writing employ distinct indices.
  • Method chaining is supported.
  • Reference counting is supported.
  • Pooling is supported.

There are a couple usage patterns of ByteBuf

  • Heap buffer. The data is stored in the heap space of the JVM, referred as a backing array.
  • Direct buffer. Data stored in off heap space.
  • Composite buffer. An aggregated view of multiple ByteBufs.

Byte-level Operations

  • Random access indexing
buffer.getByte(i)
  • Sequential access indexing
  • Discardable bytes, Readable bytes, Writable bytes

ByteBuf allocation

  • On-demand: ByteBufAllocator

Netty implements pooling with ByteBufAllocator to reduce the overhead of allocating and deallocating memory. You can obtain a reference to a ByteBufAllocator via Channel or ChannelHandlerContext.

  • Unpooled buffers

Use this when there is no reference to ByteBufAllocator. Netty provides a utility class called Unpooled for this.

Chapter 6: ChannelHandler and ChannelPipeline

The ChannelHandler family

Channel’s lifecycle:
ChannelRegistered -> 
ChannelActive (Channel registered to an EventLoop)-> 
ChannelInactive -> ChannelUnregistered

A couple common hanlders

ChannelInboundHandler, ChannelOutboundHandler,

ChannelPipeline

Every Channel created is assigned a new ChannelPipelin. A Channel can neither attach another ChannelPipeline nor detach the current one.

  • A ChannelPipeline holds the ChannelHandlers associated with a Channel.
  • A ChannelPipeline can be modified dynamically by adding & removing ChannelHandlers as needed.
  • ChannelPipeline has a rich API for invoking actions in response to inbound and outbound events.

ChannelHandlerContext represents an association between a ChannelHandler and a ChannelPipeline. It enables ChannelHandler to interact with its ChannelPipeline and other handlers.

  • The ChannelHandlerContext associated with a ChannelHandler never changes.

Relationship between Channel, ChannelPipeline, ChannelHandler and ChannelHandlerContext:

Chapter 7: EventLoop and threading model

Threading model

The basic thread pooling pattern can be described as:

  • A Thread is selected from the pool’s free list and assigned to run a submitted task (a Runnable)
  • When the task is completed, the Thread is returned to the list and becomes available for reuse.

EventLoop

Basic idea of an event loop:

The EventLoop is powered by EXACTLY ONE Thread that never changes. Note that since Netty4 ALL IO operations and events are handled by the Thread that has been assigned to the EventLoop.

Chapter 8: Bootstrapping

Bootstraping class consists of an abstract parent class and two concrete bootstrap subclasses — Bootstrap & ServerBoostrap.

Bootstrap Class

The Bootstrap class is responsible for creating channels for clients and for applications that utilize connectionless protocols.

ServerBootstrap Class

Chapter 9: Unit Testing (Skipped)

Chapter 10: The Codec Framework

What is a codec?

Codec is composed of an encoder and a decoder and each of which transforms a stream of bytes from one format to another.

Decoder

Netty’s decoders implement ChannelInBoundHandler since it is responsible for transforming inbounding data from one format to another.

Encoder

Netty’s encoders implement ChannelOutBoundHandler and transforms outbound data from one format to another.

Chapter 11: Provided ChannelHandler and Codecs

  1. Securing Netty Applications with TLS/SSL

Java supports SSL/TLS through package javax.net.ssl. Netty leverages this API by way of a ChannelHandler implementation named SslHandler, which employees an SSLEngine internally to do the actual work.

In most cases, SslHandler will be the first ChannelHandler in the ChannelPipeline.

2. Building Netty HTTP/HTTPS Applications

You need HttpRequest(Response)Decoder(Encoder) to decode the HTTP messages. Netty also provides a HttpObjectAggregator to aggregate HTTP message merge message parts into FullHttpRequest and FullHttpResponse. You can also add HTTP compression via HttpContentCompressor and HTTPS support via SslHandler.

3. Idle connections and timeouts are handled via IdleStateHandler(int, int, int, Unit).

4. Delimited protocols can be decoded using LineBasedFrameDecoder(Int) and length based protocols can be decoded using LengthFieldBasedFrameDecoder(int, int, int).

5. Writing Big Data

You can transmit a file’s content with zero-copy by creating a FileRegion from a FileInputStream and writing it to a Channel.

6. Serialize Data

Use JBoss Marshaling if possible, it is 3x faster than the default JDK serializer. Protocol Buffers is also supported via the ProtobufEncoder(Decoder).

Chapter 12: WebSocket

  1. WebSocket protocol was designed from the ground up to provide a practical solution to the problem of bidirectional data transmission on the web, allowing client and servers to transmit messages at any time and requiring them to handle message receipt asynchronously. Netty supports WebSocket well!
  2. Upgrade handshake is used to switch from standard HTTP/HTTPS to WebSocket and an application that uses WebSocket will always start with HTTP/S and then perform the upgrade.

Your ChannelPipeline is like this before WebSocket upgrade:

After the upgrade:

You can also append a SslHandler to make it secure.

Chapter 12: Broadcasting Events with UDP

Netty provides a number of classes to support UDP applications. The primary ones are here:

Chapter 14 & 15 Case Studies

Some case studies, fun read :)