I need to track individual client's connections (written, read bytes and speed(bytes per second)) in my simple http server netty app. As I understand, to do this, I have to use ChannelTrafficShapingHandler
.
What methods must be overriden and how can I do these calculations?
My ChannelInitializer:
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("codec", new HttpServerCodec())
.addLast("traffic", new TrafficShapingHandler(AbstractTrafficShapingHandler.DEFAULT_CHECK_INTERVAL))
.addLast("handler", new HttpServerHandler());
}
}
My SimpleChannelInboundHandler:
public class HttpServerHandler extends SimpleChannelInboundHandler<HttpRequest> {
private static DefaultChannelGroup activeChannels = new DefaultChannelGroup("netty-receiver", ImmediateEventExecutor.INSTANCE);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
activeChannels.add(ctx.channel());
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
if (is100ContinueExpected(req)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
}
String uri = req.getUri().toLowerCase();
Controller controller = ControllerFactory.getController(uri);
FullHttpResponse response = controller.getResponse();
if (controller instanceof HelloController) {
ctx.executor().schedule(() -> ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE), 3, TimeUnit.SECONDS);
} else {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
public static long getConnectionsQuantity() {
return activeChannels.size();
}
}
@TMS, in order to be able to get statistics, you first need to choose the level of the statistics: per channel, globally or both.
ChannelTrafficShapingHandler
: you must create one item per channel (as you did in your pipeline), it is linked to one and only one channel. The statistics are only per channel, not global.GlobalTrafficShapingHandler
: you must create it before any channel and assign it to each channel as you did but reusing the same object each time (no reallocation). The statistics are only global, not per channel.GlobalChannelTrafficShapingHandler
: you must create it before (as for GlobalTSH) and assign it to each channel (no reallocation). The statistics are global and per channel.Once you decided which one is for you, there are mainly 2 ways to get statistics:
trafficCounter()
method to access the TrafficCounter object:channelTrafficCounters()
to access all TrafficCounters for all active channels (GlobalChannelTSH only)protected void doAccounting(TrafficCounter counter)
method.You can look at one example made for Netty but not imported finally in the main stream that shows how to extend it and using it: see here and in particular how to extend GlobalChannelTSH or how to include it in your pipeline here.
Of course, you could have a look at the API that explain partially this too.
Finally, if you want to have both statistics for channel and globally, you have the choice to:
name()
) (GlobalChannelTSH is mainly intend to limit the memory impact on traffic shapping when doing it on both levels, per channel and globally, but when used only for statistics, probably not the best choice);