0

我需要在我的简单 http 服务器 netty 应用程序中跟踪单个客户端的连接(写入、读取字节和速度(每秒字节数))。据我了解,要做到这一点,我必须使用ChannelTrafficShapingHandler. 哪些方法必须被覆盖,我该如何进行这些计算?

我的 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());
    }
}

我的 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();
    }

}
4

1 回答 1

3

@TMS,为了能够获得统计信息,您首先需要选择统计信息的级别:每个频道,全局或两者。

  • ChannelTrafficShapingHandler:您必须为每个频道创建一个项目(就像您在管道中所做的那样),它链接到一个且只有一个频道。统计信息仅针对每个通道,而不是全局的。

  • GlobalTrafficShapingHandler:您必须在任何通道之前创建它并将其分配给每个通道,但每次都重用相同的对象(不重新分配)。统计数据只是全局的,而不是每个频道的。

  • GlobalChannelTrafficShapingHandler:您必须在之前创建它(对于 GlobalTSH)并将其分配给每个通道(不重新分配)。统计数据是全局的和每个通道的。

一旦你决定了哪一个适合你,主要有两种方法来获取统计信息:

  1. 通过管道访问:访问处理程序,然后:
    • 使用trafficCounter()方法访问 TrafficCounter 对象:
      • 对于通道(仅限 ChannelTSH)
      • 为全球视野(GlobalTSH 或 GlobalChannelTSH)。
    • 用于channelTrafficCounters()访问所有活动通道的所有 TrafficCounter(仅限 GlobalChannelTSH)
  2. 通过扩展基类(ChannelTSH、GlobalTSH 或 GlobalChannelTSH 之一)和具体protected void doAccounting(TrafficCounter counter)方法。

您可以查看为 Netty 制作的一个示例,但最终未在主流中导入,该示例展示了如何扩展和使用它:请参见此处,特别是如何扩展 GlobalChannelTSH如何将其包含在您的管道中

当然,您也可以查看部分解释这一点的 API 。

最后,如果您想同时获得渠道和全球的统计信息,您可以选择:

  • 要么使用 GlobalChannelTSH (只有一个一直重复使用),但你必须检查自己哪个通道连接到哪个 TrafficCounter (使用name())(GlobalChannelTSH 主要是为了限制在两个级别上进行流量整形时的内存影响,每个通道和全局,但仅用于统计时,可能不是最佳选择);
  • 要么同时使用 ChannelTSH(因此直接访问每个通道的 TrafficCounter)和 GlobalTSH(仅用于全局 TrafficCounter)。
于 2015-08-02T18:36:32.537 回答