0
votes

I'm writing a netty/websocket server app where the writes to the websocket client (e.g. browser) come from another thread (i.e. not from a websocket).

This is netty 4.0.18.Final, and my app is heavily based on the provided websocket server example.

I need to know when the websocket channel opens, so that I can save the ChannelHandlerContext so that the other thread can perform writes. I have something that works, but I'm hoping there is a more robust method.

It looks like WebSocketServerHandler.channelRead0() is called twice when the browser connects to the websocket. The ChannelHandlerContext of the second call can be used for future writes to the channel.

So my method is to take some action on the second call to channelRead0(). If I get a CloseWebSocketFrame in handleWebSocketFrame() I reset the counter.

Is there a better way?

update: the handler class look like this, after adding the userEventTriggered():

public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
   ...

   @Override
   public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
      System.out.println("read0");

      if (msg instanceof FullHttpRequest) {
        handleHttpRequest(ctx, (FullHttpRequest) msg);
      } else if (msg instanceof WebSocketFrame) {
        handleWebSocketFrame(ctx, (WebSocketFrame) msg);
      }
   }

   @Override
   public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    System.out.println("userEvent");
    if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {
        System.out.println("opening channel " + ctx.toString());
        ...    
    } else {
        super.userEventTriggered(ctx, evt);
    }
} 

And the initializer:

public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {

...

   @Override
   public void initChannel(SocketChannel ch) throws Exception {
      ChannelPipeline pipeline = ch.pipeline();
      pipeline.addLast("codec-http", new HttpServerCodec());
      pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
      pipeline.addLast("handler", new WebSocketServerHandler(statusListener));
   } 
}
1

1 Answers

0
votes

You could check for the ServerHandshakeStateEvent.HANDSHAKE_COMPLETE event like done in my chat server example, it can be used like:

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {

        ctx.pipeline().remove(HttpRequestHandler.class);

        group.writeAndFlush(new TextWebSocketFrame("Client " + ctx.channel() + " joined"));

        group.add(ctx.channel());
    } else {
        super.userEventTriggered(ctx, evt);
    }
}