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),,可以满足我的想法。
应该是没收到请求数据的结尾时,那个if (msg instanceof HttpContent)会一直满足条件,一直在收取数据。后来我将处理逻辑加到if(content instanceof LastHttpContent),,可以满足我的想法。
#2
#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) {
...
}
你要这样
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),,可以满足我的想法。
应该是没收到请求数据的结尾时,那个if (msg instanceof HttpContent)会一直满足条件,一直在收取数据。后来我将处理逻辑加到if(content instanceof LastHttpContent),,可以满足我的想法。
#2
#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) {
...
}
你要这样
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) {
...
}