HttpRequestDecoder解析http協議時,Content-Length的重要性

NettyServer:html

package wuwenlun.netty.chapter2.http;

import wuwenlun.netty.chapter2.ClientHandler;
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.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class NettyServer {
	public static void main(String[] args) {
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		
		try {
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			serverBootstrap.group(bossGroup, workerGroup)
						   .channel(NioServerSocketChannel.class)
						   .option(ChannelOption.SO_BACKLOG, 128)
						   .option(ChannelOption.SO_RCVBUF, 1024)
						   .option(ChannelOption.SO_KEEPALIVE, true)
						   .childHandler(new ChannelInitializer<NioSocketChannel>() {

								@Override
								protected void initChannel(NioSocketChannel ch) throws Exception {
									ch.pipeline().addLast(new HttpRequestDecoder());
									ch.pipeline().addLast(new HttpObjectAggregator(1024));
									ch.pipeline().addLast(new ServerHandler());
								}
							});
			
			ChannelFuture future = serverBootstrap.bind(8080).sync();
			
			future.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
}

 

NettyClient:java

package wuwenlun.netty.chapter2.http;

import java.nio.charset.Charset;

import io.netty.bootstrap.Bootstrap;
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.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class NettyClient {
	
	public EventLoopGroup group = null;
	public Bootstrap bootrap = null;
	
	public Bootstrap start() {
		group = new NioEventLoopGroup();
		bootrap = new Bootstrap();
		bootrap.group(group)
		.channel(NioSocketChannel.class)
		.option(ChannelOption.SO_KEEPALIVE, true)
		.option(ChannelOption.SO_SNDBUF, 3400)
		.handler(new ChannelInitializer<NioSocketChannel>() {

			@Override
			protected void initChannel(NioSocketChannel ch) throws Exception {
				ch.pipeline().addLast(new StringEncoder());
			}
		});
		
		return bootrap;
	}
	
	public static void main(String[] args) throws InterruptedException {
		ChannelFuture future = new NettyClient().start().connect("127.0.0.1", 8080).sync();
		String lineHeader = "GET /socketio?name=wuwenlun HTTP/1.1\r\n"+
						"Host: 127.0.0.1:8080\r\n"+
						"Connection: keep-alive\r\n"+
						"Upgrade-Insecure-Requests: 1\r\n"+
						"Content-Type: text/html\r\n"+
						"Content-Length: 20\r\n"+
						"User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36\r\n"+
						"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n"+
						"Accept-Encoding: gzip, deflate, sdch, br\r\n"+
						"Accept-Language: zh-CN,zh;q=0.8\r\n"+
						"\r\n";
		future.channel().writeAndFlush(lineHeader);
		Thread.sleep(15000);
		String content = "I Love You Forever";
		Charset charset = Charset.forName("UTF-8");
		content.getBytes(charset);
		future.channel().writeAndFlush(content);
		Thread.sleep(15000);
		future.channel().writeAndFlush("88");
		Thread.sleep(80000);
		future.channel().closeFuture().sync();
	}
}

 

ServerHandler:web

package wuwenlun.netty.chapter2.http;

import java.nio.charset.Charset;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerHandler extends ChannelInboundHandlerAdapter{

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		System.out.println("服務端開始讀取數據");
		if(msg instanceof ByteBuf) {
			ByteBuf buf = (ByteBuf)msg;
			String content = buf.toString(Charset.defaultCharset());
			System.out.println(content);
			ctx.channel().writeAndFlush("來自服務端發送:"+msg);
		}
	}

}

 

執行流程圖:bootstrap

如今回到Content-Length這個話題,當客戶端發送的請求體內容長度沒有達到Content-Length的數值時,會放棄往下執行,等待後面客戶端發來的請求體內容,當數據總和達到Content-Length的數值時(包括前面的請求),則繼續往下執行。那麼你可能會提出一個問題,當前面的客戶端請求(前面兩次請求)沒有達到Content-Length的長度時,而最後一次請求達到了(第三次請求)。第三次請求是如何知道前面兩次請求的狀態呢,不如數據分析到什麼地步了啊,分析到哪裏了啊。看netty的register分析文章。app

相關文章
相關標籤/搜索