netty权威指南 学习笔记http

 李林峰的《netty权威指南》,从Java的NIO开始介绍,后面介绍TCP粘包拆包。中级篇介绍编解码技术。

第10章介绍了HTTP及netty HTTP+XML的技术。

因为xml实际使用接口中很少了,所以用json格式来替换下。

pom准备:

<dependency>
			<groupId>io.netty</groupId>
			<artifactId>netty-all</artifactId>
			<version>4.1.17.Final</version>			
		</dependency>
<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
        <dependency>
		    <groupId>org.json</groupId>
		    <artifactId>json</artifactId>
		    <version>20171018</version>
		</dependency>

简单的请求过程:

1、Client向Server发送http请求。

2、Server端对http请求进行解析。

3、Server端向client发送http响应。

4、Client对http响应进行解析。


服务器端

public class HttpFileServer {

    private static final String DEFAULT_URL = "/";

    public void run(final int port, final String url) 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
			protected void initChannel(SocketChannel ch)
				throws Exception {
			    ch.pipeline().addLast("http-decoder",
				    new HttpRequestDecoder()); // 请求消息解码器
			    ch.pipeline().addLast("http-aggregator",
				    new HttpObjectAggregator(65536));// 目的是将多个消息转换为单一的request或者response对象
			    ch.pipeline().addLast("http-encoder",
				    new HttpResponseEncoder());//响应解码器
			    ch.pipeline().addLast("http-chunked",
				    new ChunkedWriteHandler());//目的是支持异步大文件传输()
			    ch.pipeline().addLast("fileServerHandler",
				    new HttpFileServerHandler(url));// 业务逻辑
			}
		    });
	    ChannelFuture future = b.bind("10.253.8.138", port).sync();
	    System.out.println("HTTP文件目录服务器启动,网址是 : " + "http://10.253.8.138:"
		    + port + url);
	    future.channel().closeFuture().sync();
	} finally {
	    bossGroup.shutdownGracefully();
	    workerGroup.shutdownGracefully();
	}
    }

    public static void main(String[] args) throws Exception {
	int port = 8080;
	if (args.length > 0) {
	    try {
		port = Integer.parseInt(args[0]);
	    } catch (NumberFormatException e) {
		e.printStackTrace();
	    }
	}
	String url = DEFAULT_URL;
	if (args.length > 1)
	    url = args[1];
	new HttpFileServer().run(port, url);
    }
}

上面基本上是书中demo,就是把xml的编解码替换下。

public class HttpFileServerHandler  extends ChannelInboundHandlerAdapter {
    private static final AsciiString CONTENT_TYPE = new AsciiString("Content-Type");
    private static final AsciiString CONTENT_LENGTH = new AsciiString("Content-Length");
    private static final AsciiString CONNECTION = new AsciiString("Connection");
    private static final AsciiString KEEP_ALIVE = new AsciiString("keep-alive");
	
    private final String url;

    public HttpFileServerHandler(String url) {
	this.url = url;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
	if (!(msg instanceof FullHttpRequest))  {
		  //错误处理
	    return;
	}
	
    FullHttpRequest request = (FullHttpRequest) msg;//客户端的请求对象
    JSONObject responseJson = new JSONObject();//新建一个返回消息的Json对象
    //把客户端的请求数据格式化为Json对象
    JSONObject requestJson = null;
    try{
       requestJson = new JSONObject(parseJosnRequest(request));
    }catch(Exception e)
    {
        ResponseJson(ctx,request,new String("error json"));
        return;
    }
    
	final String uri = request.uri();
	if (request.method() == HttpMethod.POST) {
		if(uri.equals("/bmi"))
	    { 
	        //计算体重质量指数
	        double height =0.01* requestJson.getDouble("height");
	        double weight =requestJson.getDouble("weight");
	        double bmi =weight/(height*height);
	        bmi =((int)(bmi*100))/100.0;
	        responseJson.put("bmi", bmi +"");
	
	    }else{
	    	  //错误处理
	        responseJson.put("error", "404 Not Find");
	    }
	}else{
    	  //错误处理
        responseJson.put("error", "404 Not Find");
    }
	  //向客户端发送结果
    ResponseJson(ctx,request,responseJson.toString());
    }
    private void ResponseJson(ChannelHandlerContext ctx, FullHttpRequest request, String jsonStr) {
		// TODO Auto-generated method stub
    	 boolean keepAlive = HttpUtil.isKeepAlive(request);
         byte[] jsonByteByte = jsonStr.getBytes();
         FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(jsonByteByte));
         response.headers().set(CONTENT_TYPE, "text/json");
         response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
         
         if (keepAlive) {           
             response.headers().set(CONNECTION, KEEP_ALIVE);           
         }
         ctx.writeAndFlush(response);
	}

	//获取请求的内容
    private String parseJosnRequest(FullHttpRequest request) {
    	ByteBuf jsonBuf = request.content();
        String jsonStr = jsonBuf.toString(CharsetUtil.UTF_8);
        return jsonStr;
	}

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

}

这个参考网上的例子,把书上的看文件列表,替换成计算体重的bmi方法。


我们用postman测试下。可以正常返回数据。

客户端代码

还可以用client测试代码。

public class HttpJsonClient {

    public void connect(String host, int port) throws Exception {
	// 配置客户端NIO线程组
	EventLoopGroup group = new NioEventLoopGroup();
	try {
	    Bootstrap b = new Bootstrap();
	    b.group(group).channel(NioSocketChannel.class)
		    .option(ChannelOption.TCP_NODELAY, true)
		    .handler(new ChannelInitializer<SocketChannel>() {
			@Override
			public void initChannel(SocketChannel ch)
				throws Exception {
			    ch.pipeline().addLast("http-decoder",
				    new HttpResponseDecoder());
			    ch.pipeline().addLast("http-aggregator",
				    new HttpObjectAggregator(65536));			
			    ch.pipeline().addLast("http-encoder",
				    new HttpRequestEncoder());			   
			    ch.pipeline().addLast(new HttpJsonClientHandle());
			}
		    });

	    // 发起异步连接操作
	    ChannelFuture f = b.connect(new InetSocketAddress(port)).sync();
	    
	    //
	    URI uri = new URI("/bmi");
	    String msg = "{\"height\":175,\"weight\":70}";
	    DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST,
		         uri.toASCIIString(), Unpooled.wrappedBuffer(msg.getBytes("UTF-8")));
	    // 构建http请求
        request.headers().set(HttpHeaders.Names.HOST, host);
        request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes());
	    // 发送http请求
        f.channel().writeAndFlush(request);
	    
	    // 当代客户端链路关闭
	    f.channel().closeFuture().sync();
	} finally {
	    // 优雅退出,释放NIO线程组
	    group.shutdownGracefully();
	}
    }

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
	int port = 8080;
	if (args != null && args.length > 0) {
	    try {
		port = Integer.valueOf(args[0]);
	    } catch (NumberFormatException e) {
		// 采用默认值
	    }
	}
	new HttpJsonClient().connect("127.0.0.1",port);
    }
}

对应的handle

public class HttpJsonClientHandle extends ChannelInboundHandlerAdapter {


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

    @Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    	
    	if (msg instanceof HttpResponse)
        {
            HttpResponse response = (HttpResponse) msg;
            System.out.println("header:" + response.headers().names().toString());
        }
        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();
        }
    }

}
可以看下client的调用输出:

header:io.netty.handler.codec.HeadersUtils$CharSequenceDelegatingStringSet@b56f674
{"bmi":"22.85"}

***********************************************************************

这是学习netty的第一个程序,有些过时的方法。

书上上来没有介绍netty的模型等基础知识,更侧重介绍了netty与Java的NIO的对比。

所以即使能跑起来,还是需要去学习netty的知识。


参考:

http://blog.csdn.net/shenzhan168/article/details/53142459

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值