Skip navigation

WebSocket Enhancement

Netty has had WebSocket support for quite a while now, and it is easy to get up an running quickly with the existing examples. The example provided with Netty, consists of a handler which takes care of the HTTP Upgrade handshake, and also manages the WebSocket protocol. If you need to service http requests, for example serving static files, in addition to WebSocket calls then this approach works great.  

But if all you want to do is create a custom application protocol on top of WebSocket and only service WebSocket requests, then the above solution is a fair amount of code that you'll have to maintain yourself. So, we set out to try to simplify this and this post describes what we came up with.

Handling a TextSocketFrame

Below is an example of implementing a handler that will receive a TextWebSocketFrame :

public class CustomTextFrameHandler extends ChannelInboundMessageHandlerAdapter<TextWebSocketFrame> {
@Override
public void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
String request = frame.getText();
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
}
}
view raw gistfile1.java hosted with ❤ by GitHub

The text content is retrieved by calling getText, and can then be parsed as required by the application protocol. This might involve parsing the String as JSON or whatever the protocol in question dictates. 

Bootstrapping Netty

Now, lets take a look at what is needed to bootstrap Netty:

public static void main(String[] args) throws Exception {
final ServerBootstrap sb = new ServerBootstrap();
try {
sb.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(final SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new HttpRequestDecoder(),
new HttpChunkAggregator(65536),
new HttpResponseEncoder(),
new WebSocketServerProtocolHandler("/websocket"),
new CustomTextFrameHandler());
}
});
final Channel ch = sb.bind().sync().channel();
System.out.println("Web socket server started at port " + port);
ch.closeFuture().sync();
} finally {
sb.shutdown();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

As you can see the CustomTextFrameHandler from the previous code example is the last handler added, and right before it, we have a new handler named WebSocketServerProtocolHandler.

An example has been included in Netty which uses the above code for the server side, and a simple html page as the WebSocket client.

Netty 3.x Support

This feature has also been back-ported to Netty 3.x. The CustomTextFrameHandler class would then look something like this:

public class CustomTextFrameHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if (e.getMessage() instanceof TextWebSocketFrame) {
TextWebSocketFrame frame = (TextWebSocketFrame) e.getMessage();
ctx.getChannel().write(new TextWebSocketFrame(frame.getText().toUpperCase()));
}
}
}
view raw gistfile1.java hosted with ❤ by GitHub

An example has been included in Netty which uses the above code for the server side, and a simple html page as the WebSocket client.