Netty4.x官方example的问题,浏览器访问执行handler中channelRead方法次数

RegnoiX 发布于 2013/10/24 12:59
阅读 4K+
收藏 0

MySQL连接为什么挂死了?别踩坑!>>>

刚刚接触网络编程,现在情况是一个client发送出的事http请求,server用的事tcp,需要中间转接一下,准备用netty来做这个转接的服务。

从官网上下载的example准备学习下,程序运行起来后,用chrome,ie10访问http://127.0.0.1:8080/都会访问HttpHelloWorldServerHandler中的channelRead方法4次,

用MyEclipse内置的浏览器访问就只调用2次,不知道是什么原理?代码如下,


public class HttpHelloWorldServer {

    private final int port;

    public HttpHelloWorldServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {
        // Configure the server.
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.option(ChannelOption.SO_BACKLOG, 1024);
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new HttpHelloWorldServerInitializer());

            Channel ch = b.bind(port).sync().channel();
            ch.closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        } else {
            port = 8080;
        }
        new HttpHelloWorldServer(port).run();
    }
}


public class HttpHelloWorldServerHandler extends ChannelInboundHandlerAdapter {
    private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    	System.out.println("invoke channelRead msg.class="+msg.getClass());
        if (msg instanceof HttpRequest) {
            HttpRequest req = (HttpRequest) msg;

            if (is100ContinueExpected(req)) {
                ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
            }
            boolean keepAlive = isKeepAlive(req);
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(CONTENT));
            response.headers().set(CONTENT_TYPE, "text/plain");
            response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
            if (!keepAlive) {
                ctx.write(response).addListener(ChannelFutureListener.CLOSE);
            } else {
                response.headers().set(CONNECTION, Values.KEEP_ALIVE);
                ctx.write(response);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline p = ch.pipeline();

        // Uncomment the following line if you want HTTPS
        //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
        //engine.setUseClientMode(false);
        //p.addLast("ssl", new SslHandler(engine));

        p.addLast("codec", new HttpServerCodec());
        p.addLast("handler", new HttpHelloWorldServerHandler());
    }
}

用chrome,ie10访问时输出  

invoke channelRead msg.class=class io.netty.handler.codec.http.DefaultHttpRequest
invoke channelRead msg.class=class io.netty.handler.codec.http.LastHttpContent$1
invoke channelRead msg.class=class io.netty.handler.codec.http.DefaultHttpRequest
invoke channelRead msg.class=class io.netty.handler.codec.http.LastHttpContent$1
用MyEclipse内置的浏览器访问

invoke channelRead msg.class=class io.netty.handler.codec.http.DefaultHttpRequest
invoke channelRead msg.class=class io.netty.handler.codec.http.LastHttpContent$1
本来想在HttpHelloWorldServerHandler.channelRead中的

if (msg instanceof HttpRequest) {
  ...
 }
处理下逻辑,现在不知道咋办了

特此求教,谢谢

@红薯 @石头哥哥 @JavaGG

加载中
1
_DeepBlue
_DeepBlue
因该是浏览器发了一次favicon.ico请求
0
EF0718
EF0718
我也碰到过类似的情况,我感觉应该是每次接收数据的时候ByteBuf满了,就会把请求截成两段。
RegnoiX
RegnoiX
就是一个普通的http请求,debug时第一次进入request中的内容应该是全的。
0
EF0718
EF0718
Netty读请求数据时,首先读数据到新创建的固定大小的Buffer中,当Buffer满或者没有数据可读 时,直接调用handler来处理数据已经取得的数据。普通的http请求头的长度有大有小,不同的请求发生器(浏览器),http请求头应该是不一样的。你可以用Fiddler截取一下chrome、ie10MyEclipse内置的浏览器发送出来的请求的大小,比较一下。也可自己构造不同长度的请求头向Netty发送。作参考。
0
RegnoiX
RegnoiX
用fiddler看了下果然是 favicon请求,谢谢 @Missher  @EF0718
0
西瓜胖子
西瓜胖子
//加上这段代码就知道了
HttpRequest httpRequest = (HttpRequest) msg;
URI uri = new URI(httpRequest.uri());
if("/favicon.ico".equals(uri.getPath())){
    System.out.println("请求favicon.ico");
}
返回顶部
顶部