• 基于Netty4的HttpServer和HttpClient的简单实现


    Netty的主页:http://netty.io/index.html

    使用的Netty的版本:netty-4.0.23.Final.tar.bz2 ‐ 15-Aug-2014 (Stable, Recommended)

    Http 消息格式:

    Http request:

    Method path-to-resource HTTPVersion-number
    Header-name-1: value1
    Header-name-2: value2
    
    Optional request body

    Http response:

    HTTP/Version-number response-code response-phrase 
    Header-name-1: value1
    Header-name-2: value2
    
    Optional response body

    实现一个简单的Http请求及响应过程:

    1、Client向Server发送http请求。

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

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

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

    Netty中Http request消息格式:

    Netty中Http response消息格式:

    代码实例:

    Http Server:

    package com.netty.test;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    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 HttpServer {
    
        private static Log log = LogFactory.getLog(HttpServer.class);
        
        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 {
                                        // server端发送的是httpResponse,所以要使用HttpResponseEncoder进行编码
                                        ch.pipeline().addLast(new HttpResponseEncoder());
                                        // server端接收到的是httpRequest,所以要使用HttpRequestDecoder进行解码
                                        ch.pipeline().addLast(new HttpRequestDecoder());
                                        ch.pipeline().addLast(new HttpServerInboundHandler());
                                    }
                                }).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 {
            HttpServer server = new HttpServer();
            log.info("Http Server listening on 8844 ...");
            server.start(8844);
        }
    }

    响应请求的HttpServerInboundHandler:

    package com.netty.test;
    
    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 org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    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 HttpServerInboundHandler extends ChannelInboundHandlerAdapter {
    
        private static Log log = LogFactory.getLog(HttpServerInboundHandler.class);
    
        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
    = "I am OK"; FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(res.getBytes("UTF-8"))); response.headers().set(CONTENT_TYPE, "text/plain"); 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) { log.error(cause.getMessage()); ctx.close(); } }

    Http Client:

    package com.netty.test;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.Unpooled;
    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.NioSocketChannel;
    import io.netty.handler.codec.http.DefaultFullHttpRequest;
    import io.netty.handler.codec.http.HttpHeaders;
    import io.netty.handler.codec.http.HttpMethod;
    import io.netty.handler.codec.http.HttpRequestEncoder;
    import io.netty.handler.codec.http.HttpResponseDecoder;
    import io.netty.handler.codec.http.HttpVersion;
    
    import java.net.URI;
    
    public class HttpClient {
        public void connect(String host, int port) throws Exception {
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                Bootstrap b = new Bootstrap();
                b.group(workerGroup);
                b.channel(NioSocketChannel.class);
                b.option(ChannelOption.SO_KEEPALIVE, true);
                b.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        // 客户端接收到的是httpResponse响应,所以要使用HttpResponseDecoder进行解码
                        ch.pipeline().addLast(new HttpResponseDecoder());
                        // 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码
                        ch.pipeline().addLast(new HttpRequestEncoder());
                        ch.pipeline().addLast(new HttpClientInboundHandler());
                    }
                });
    
                // Start the client.
                ChannelFuture f = b.connect(host, port).sync();
    
                URI uri = new URI("http://127.0.0.1:8844");
                String msg = "Are you ok?";
                DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
                        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().write(request);
                f.channel().flush();
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
            }
    
        }
    
        public static void main(String[] args) throws Exception {
            HttpClient client = new HttpClient();
            client.connect("127.0.0.1", 8844);
        }
    }

    处理Server响应的HttpClientInboundHandler:

    package com.netty.test;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.handler.codec.http.HttpContent;
    import io.netty.handler.codec.http.HttpHeaders;
    import io.netty.handler.codec.http.HttpResponse;
    
    public class HttpClientInboundHandler extends ChannelInboundHandlerAdapter {
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof HttpResponse) 
            {
                HttpResponse response = (HttpResponse) msg;
                System.out.println("CONTENT_TYPE:" + response.headers().get(HttpHeaders.Names.CONTENT_TYPE));
            }
            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();
            }
        }
    }

    参考代码:https://github.com/luxiaoxun/Code4Java

    参考:

    https://github.com/netty/netty

  • 相关阅读:
    python练习册 每天一个小程序 第0006题
    python练习册 每天一个小程序 第0005题
    [happyctf]部分writeup
    python练习册 每天一个小程序 第0004题
    [实验吧](web)因缺思厅的绕过 源码审计绕过
    python练习册 每天一个小程序 第0002题
    poj2185 Milking Grid
    hdu1711 Number Sequence
    poj1961 Period
    lightOJ 1017 Brush (III) DP
  • 原文地址:https://www.cnblogs.com/luxiaoxun/p/3959450.html
Copyright © 2020-2023  润新知