Netty,接收到一个请求,但是代码段执行了两次,为什么?

时间:2022-09-13 20:44:26
Server.java内容如下:
package demo.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture; 
import io.netty.channel.ChannelInitializer; 
import io.netty.channel.ChannelOption; 
import io.netty.channel.EventLoopGroup; 
import io.netty.channel.nio.NioEventLoopGroup; 
import io.netty.channel.socket.SocketChannel; 
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder; 
import io.netty.handler.codec.http.HttpResponseEncoder; 

public class Server {
    
    public void start(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                                @Override
                                public void initChannel(SocketChannel ch) throws Exception {
                                    ch.pipeline().addLast(new HttpResponseEncoder());
                                    ch.pipeline().addLast(new HttpRequestDecoder());
                                    ch.pipeline().addLast(new ServerHandler());
                                }
                            }).option(ChannelOption.SO_BACKLOG, 128) 
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(port).sync();

            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        Server server = new Server();
        server.start(8844);
    }
}


ServerHandle.java内容如下:
package demo.server;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

import java.text.SimpleDateFormat;
import java.util.Date;

import demo.tools.*;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpRequest;

public class ServerHandler extends ChannelInboundHandlerAdapter {

    private HttpRequest request;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        if (msg instanceof HttpRequest) {
            request = (HttpRequest) msg;
            String uri = request.getUri();
            System.out.println("Uri:" + uri);
        }
        if (msg instanceof HttpContent) {
            HttpContent content = (HttpContent) msg;
            ByteBuf buf = content.content();
         //  System.out.println(buf.toString(io.netty.util.CharsetUtil.UTF_8));
            buf.release();
            String res =null;
            Parameter Pa = new Parameter();
            String[] first = Pa.readParameter(Pa.readParameter("first")).split(",");
            String[] second = Pa.readParameter(Pa.readParameter("second")).split(",");
            String[] third = Pa.readParameter(Pa.readParameter("third")).split(",");
            //String[] fourth = Pa.readParameter(Pa.readParameter("fourth")).split(",");
            int randomData=(int) (Math.random()*1000)%1000;
            int randomSleep=(int) (Math.random()*10000);
            if(randomData>Integer.parseInt(first[0])&&randomData<=Integer.parseInt(first[1])){
             res = Base64_EN_DE.getFromBASE64(Pa.readParameter("r"+Pa.readParameter("first")));
             System.out.print(res);
            }
            else if(randomData>Integer.parseInt(second[0])&&randomData<=Integer.parseInt(second[1])){
             res = Base64_EN_DE.getFromBASE64(Pa.readParameter("r"+Pa.readParameter("second")));
             System.out.print(res);
            }
            else if(randomData>Integer.parseInt(third[0])&&randomData<=Integer.parseInt(third[1])){
             res = Base64_EN_DE.getFromBASE64(Pa.readParameter("r"+Pa.readParameter("third")));
             System.out.print(res);
            }
            else {
             Thread.sleep(randomSleep);
             //停止10s以内的随机时间,再返回结果
             res = Base64_EN_DE.getFromBASE64(Pa.readParameter("r"+Pa.readParameter("first")));
             System.out.print(res);
            }
            Date now=new Date();
            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1,
                    OK, Unpooled.wrappedBuffer(res.getBytes("UTF-8")));
            response.headers().set(CONTENT_TYPE, "text/xml;charset=UTF-8");//只返回xml的内容
            response.headers().set("Date", now);
            response.headers().set(CONTENT_LENGTH,
                    response.content().readableBytes());
            if (HttpHeaders.isKeepAlive(request)) {
                response.headers().set(CONNECTION, Values.KEEP_ALIVE);
            }
            ctx.write(response);
            ctx.flush();
        }
    }

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

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }

}



以上是我按照网上的例子,改的netty实验代码。还有一些读配置文件和写日志的文件没写到这里来,主要就是这两个文件了。现在问题是:我启动了这个server,post了一个接口请求到“localhost:8844”,单步调试时发现,ServerHandler 的channelRead方法的 if (msg instanceof HttpRequest)只进入一次,但是ServerHandler 的channelRead方法的    if (msg instanceof HttpContent)代码段,则会进入两次,请问是什么原因??

3 个解决方案

#1


请求body数据较长的时候,执行了两遍,较短时执行了一遍。

应该是没收到请求数据的结尾时,那个if (msg instanceof HttpContent)会一直满足条件,一直在收取数据。后来我将处理逻辑加到if(content instanceof LastHttpContent),,可以满足我的想法。

#2


该回复于2016-09-05 11:12:32被管理员删除

#3


这是HttpRequestDecoder把请求拆分成HttpRequest和HttpContent两部分了,
你要这样
pipeline.addLast("decoder",new HttpRequestDecoder());  //把 ByteBuf 解码到 HttpRequest/HttpRespone 和 HttpContent、LastHttpContent
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(1024*1024*64));// 将 解码到的多个http消息合成一个FullHttpRequest/FullHttpRespone

然后在Handler里,就只接收到一个FullHttpRequest了
if (msg instanceof FullHttpRequest) {
...
}

#1


请求body数据较长的时候,执行了两遍,较短时执行了一遍。

应该是没收到请求数据的结尾时,那个if (msg instanceof HttpContent)会一直满足条件,一直在收取数据。后来我将处理逻辑加到if(content instanceof LastHttpContent),,可以满足我的想法。

#2


该回复于2016-09-05 11:12:32被管理员删除

#3


这是HttpRequestDecoder把请求拆分成HttpRequest和HttpContent两部分了,
你要这样
pipeline.addLast("decoder",new HttpRequestDecoder());  //把 ByteBuf 解码到 HttpRequest/HttpRespone 和 HttpContent、LastHttpContent
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(1024*1024*64));// 将 解码到的多个http消息合成一个FullHttpRequest/FullHttpRespone

然后在Handler里,就只接收到一个FullHttpRequest了
if (msg instanceof FullHttpRequest) {
...
}