为了账号安全,请及时绑定邮箱和手机 立即绑定

Netty实现简单HTTP代理服务器

标签:
安全

作者: Zephery
个人网址: http://www.wenzhihuai.com
本文为作者原创,转载请注明出处: https://www.cnblogs.com/w1570631036/p/9665385.htm

自上次使用Openresty+Lua+Nginx的来加速自己的网站,用上了比较时髦的技术,感觉算是让自己的网站响应速度达到极限了,直到看到了Netty,公司就是打算用Netty来替代Openresty这一套,所以,自己也学了好久,琢磨了好一趟才知道怎么用,现在用来写一套HTTP代理服务器吧,之后再测试一下性能。

之前相关的文章如下:
【网页加速】lua redis的二次升级
使用Openresty加快网页速度

一、Netty中的HTTP

参考自《Netty实战》

一个完整的HttpRequest请求

FullHttpRequest:

5ba1122700016fe613160400.jpg


  1. HTTP Request 第一部分是包含的头信息

  2. HttpContent 里面包含的是数据,可以后续有多个 HttpContent 部分

  3. LastHttpContent 标记是 HTTP request 的结束,同时可能包含头的尾部信息

  4. 完整的 HTTP request

一个完整的HttpResponse请求

FullHttpResponse:

5ba112280001ff9213260332.jpg


  1. HTTP response 第一部分是包含的头信息

  2. HttpContent 里面包含的是数据,可以后续有多个 HttpContent 部分

  3. LastHttpContent 标记是 HTTP response 的结束,同时可能包含头的尾部信息

  4. 完整的 HTTP response

二、Netty实现HTTP代理服务器的流程

在实现Http代理服务器之前,我们先来查看一下Netty实现代理服务器的完整流程:

5ba112290001071f08390397.jpg


Netty的Http服务的流程是:
1、Client向Server发送http请求,在通常的情况中,client一般指的是浏览器,也可以由自己用netty实现一个客户端。此时,客户端需要用到HttpRequestEncoder将http请求进行编码。
2、Server端对http请求进行解析,服务端中,需要用到HttpRequestDecoder来对请求进行解码,然后实现自己的业务需求。
3、Server端向client发送http响应,处理完业务需求后,将相应的内容,用HttpResponseEncoder进行编码,返回数据。
4、Client对http响应进行解析,用HttpResponseDecoder进行解码。

而Netty实现Http代理服务器的过程跟上面的所说无意,只不过是在自己的业务层增加了回源到tomcat服务器这一过程。结合上自己之前实现过的用OpenResty+Nginx来做代理服务器这一套,此处的Netty实现的过程也与此类似。此处粘贴一下OpenResty+Nginx实现的流程图:

5ba1122900014b7a05740656.jpg


而使用了Netty之后,便是将中间的OpenResty+Nginx换成了Netty,下面我们来看一下具体的实现过程。

三、主要代码如下:

HttpServer

public class HttpServer {    public void start(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .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 HttpServerHandler());                            //增加自定义实现的Handler
                            ch.pipeline().addLast(new HttpServerCodec());
                        }
                    }).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();
        server.start(8080);
    }
}

HttpServerHandler

@Slf4jpublic class HttpServerHandler extends ChannelInboundHandlerAdapter {    private RedisUtil redisUtil = new RedisUtil();    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {        if (msg instanceof HttpRequest) {
            DefaultHttpRequest request = (DefaultHttpRequest) msg;
            String uri = request.uri();            if ("/favicon.ico".equals(uri)) {                return;
            }
            log.info(new Date().toString());
            Jedis jedis = redisUtil.getJedis();
            String s = jedis.get(uri);            if (s == null || s.length() == 0) {                //这里我们的处理是回源到tomcat服务器进行抓取,然后
                //将抓取的内容放回到redis里面
                try {
                    URL url = new URL("http://119.29.188.224:8080" + uri);
                    log.info(url.toString());
                    URLConnection urlConnection = url.openConnection();
                    HttpURLConnection connection = (HttpURLConnection) urlConnection;
                    connection.setRequestMethod("GET");                    //连接
                    connection.connect();                    //得到响应码
                    int responseCode = connection.getResponseCode();                    if (responseCode == HttpURLConnection.HTTP_OK) {
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader
                                (connection.getInputStream(), StandardCharsets.UTF_8));
                        StringBuilder bs = new StringBuilder();
                        String l;                        while ((l = bufferedReader.readLine()) != null) {
                            bs.append(l).append("\n");
                        }
                        s = bs.toString();
                    }
                    jedis.set(uri, s);
                    connection.disconnect();
                } catch (Exception e) {
                    log.error("", e);                    return;
                }
            }
            jedis.close();
            FullHttpResponse response = new DefaultFullHttpResponse(
                    HTTP_1_1, OK, Unpooled.wrappedBuffer(s != null ? s
                    .getBytes() : new byte[0]));
            response.headers().set(CONTENT_TYPE, "text/html");
            response.headers().set(CONTENT_LENGTH,
                    response.content().readableBytes());
            response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            ctx.write(response);
            ctx.flush();
        } else {            //这里必须加抛出异常,要不然ab测试的时候一直卡住不动,暂未解决
            throw new Exception();
        }
    }    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        ctx.close();
    }
}

四、性能测试

下面的是ab测试,在1GHz、2G内存的centos7机器(阿里云服务器)下进行测试,测试命令ab -c 100 -n 10000 localhost:8000/,并发数为100,总数为10000。

性能:

5ba1122a0001248317820316.jpg


整体响应时间的分布比(单位:ms):

5ba1122a0001162817180240.jpg


看完之后,我自己也震惊了,Netty实现的不仅稳定、吞吐率还比OpenResty的高出一倍,OpenResty的居然还有那么多的失败次数,不知是不是我的代码的问题还是测试例子不规范,至今,我还是OpenResty的脑残粉。总体的来说,Netty实现的服务器性能还是比较强的,不仅能够快速地开发高性能的面向协议的服务器和客户端,还可以在Netty上轻松实现各种自定义的协议。

五、源码地址

https://github.com/Zephery/myway

参考:

  1. 《Netty实战》

  2. 基于Netty4构建HTTP服务----浏览器访问和Netty客户端访问


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中

慕标琳琳

手记
粉丝
18
获赞与收藏
140

关注作者,订阅最新文章

阅读免费教程

  • Java 并发原理入门教程
    26个小节 37427 552
  • HTTP 入门教程
    28个小节 36421 627
  • 后端通用面试教程
    41个小节 28764 323
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 分销返利 帮助中心 APP下载
官方微信
返回顶部

举报

0/150
提交
取消

深圳SEO优化公司十堰网站设计铜川建网站价格庆阳网站开发哪家好韶关百度爱采购价格延安模板制作价格日照企业网站建设哪家好邯郸企业网站设计报价丹东推广网站公司扬州外贸网站制作公司大浪阿里店铺托管哪家好连云港网站设计九江百姓网标王哪家好吴忠至尊标王报价长治关键词按天计费公司渭南网站搭建多少钱扬州百度seo哪家好衡水网站优化推广公司大理SEO按天计费哪家好苏州关键词排名包年推广报价南阳关键词排名包年推广价格邯郸高端网站设计报价淮北至尊标王公司商洛网站制作设计莆田seo网站推广价格贵港网站推广工具报价乌海如何制作网站哪家好大同外贸网站设计报价安阳网站优化价格潜江seo优化公司鞍山百度竞价推荐歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化