使用Netty3或Netty4发布Http协议服务

现在是2018年1月11日18:12分,已经是下班时间了,小Alan今天给大家简单的介绍一下Netty,让大家以后在使用到Netty的时候能够有一定的了解和基础,这样深入学习Netty以及以后灵活应用这门技术也就不在话下了,万丈高楼平地起,程序猿们平时还是要注重积累,多花些时间在技术上面,如果实在对代码提不起兴趣就早点规划好自己的发展路线,死磕着也没什么必要,对自己没啥好处,但是如果你至少不讨厌编程,那么还是多多学习吧!

Netty是什么

Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

Netty的架构

Netty的特性

设计:

------统一的API,适用于不同的协议(阻塞和非阻塞)

------基于灵活、可扩展的事件驱动模型

------高度可定制的线程模型

------可靠的无连接数据Socket支持(UDP)

性能:

------更好的吞吐量,低延迟

------更省资源

------尽量减少不必要的内存拷贝

安全:

------完整的SSL/TLS和STARTTLS的支持

------能在Applet与谷歌Android的限制环境运行良好

健壮性:

------不再因过快、过慢或超负载连接导致OutOfMemoryError

------不再有在高速网络环境下NIO读写频率不一致的问题

易用:

------完善的Java doc,用户指南和样例

------简洁简单

------仅依赖于JDK1.5

Netty怎么用

小Alan教大家使用Netty3或Netty4发布Http协议服务接口,来引导大家进入Netty的世界。

Netty3实现Http协议服务接口步骤:

第一步:创建Http业务处理服务类,代码如下

 1 package com.alanlee.http;
 2
 3 import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
 4 import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
 5
 6 import org.jboss.netty.buffer.ChannelBuffer;
 7 import org.jboss.netty.buffer.DynamicChannelBuffer;
 8 import org.jboss.netty.channel.Channel;
 9 import org.jboss.netty.channel.ChannelFuture;
10 import org.jboss.netty.channel.ChannelFutureListener;
11 import org.jboss.netty.channel.ChannelHandlerContext;
12 import org.jboss.netty.channel.ExceptionEvent;
13 import org.jboss.netty.channel.MessageEvent;
14 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
15 import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
16 import org.jboss.netty.handler.codec.http.HttpRequest;
17 import org.jboss.netty.handler.codec.http.HttpResponse;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 /**
22  * HTTP服务业务处理类.
23  *
24  * @author AlanLee
25  * @version 2018/01/11
26  *
27  */
28 public class HttpServerHandler extends SimpleChannelUpstreamHandler
29 {
30
31     /**
32      * 日志类.
33      */
34     protected static final Logger LOGGER = LoggerFactory.getLogger(HttpServerHandler.class);
35
36     @Override
37     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception
38     {
39
40         HttpRequest request = (HttpRequest) e.getMessage();
41         String method = request.getMethod().getName();
42         String url = request.getUri().toLowerCase();
43         System.out.println(method);
44         System.out.println(url);
45
46         // 接收请求内容并打印
47         ChannelBuffer buffer = request.getContent();
48         String requestStr = new String(buffer.array(), "UTF-8");
49         System.out.println(requestStr);
50
51         // 处理响应消息
52         HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
53         ChannelBuffer responseBuffer = new DynamicChannelBuffer(2048);
54         responseBuffer.writeBytes("你是猪吗?".getBytes("UTF-8"));
55         response.setContent(responseBuffer);
56         // 返回内容的MIME类型
57         response.setHeader("Content-Type", "text/html; charset=UTF-8");
58         // 响应体的长度
59         response.setHeader("Content-Length", response.getContent().writerIndex());
60         Channel ch = e.getChannel();
61
62         // 响应给客户端
63         ChannelFuture f = ch.write(response);
64
65         // 数据发送完毕,则关闭连接通道.
66         f.addListener(new ChannelFutureListener()
67         {
68             public void operationComplete(ChannelFuture future) throws Exception
69             {
70                 future.getChannel().close();
71             }
72         });
73     }
74
75     /**
76      * 发生异常
77      */
78     @Override
79     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
80     {
81         LOGGER.error("exceptionCaught(): ", e.getCause());
82         e.getCause().printStackTrace();
83     }
84
85 }

第二步:创建Http管道类工厂用来联结Http业务处理服务类,代码如下

 1 package com.alanlee.http;
 2
 3 import org.jboss.netty.channel.ChannelPipeline;
 4 import org.jboss.netty.channel.ChannelPipelineFactory;
 5 import org.jboss.netty.channel.Channels;
 6 import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
 7 import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
 8
 9 /**
10  * HTTP管道类工厂.
11  *
12  * @author AlanLee
13  * @version 2018/01/11
14  *
15  */
16 public class ServerPipelineFactory implements ChannelPipelineFactory
17 {
18
19     /**
20      * 获取管道.
21      *
22      * @return ChannelPipeline 管道
23      */
24     public ChannelPipeline getPipeline()
25     {
26         ChannelPipeline pipeline = Channels.pipeline();
27         System.out.println("initChannel pipeline");
28         // 解码
29         pipeline.addLast("decoder", new HttpRequestDecoder(1024, 1024, 1000 * 1024));
30         // 编码
31         pipeline.addLast("encoder", new HttpResponseEncoder());
32         // 请求的业务类
33         pipeline.addLast("handler", new HttpServerHandler());
34         return pipeline;
35     }
36
37 }

最后,让我们利用Netty3来发布Http协议服务接口,代码如下

 1 package com.alanlee.http;
 2
 3 import java.net.InetSocketAddress;
 4 import java.util.concurrent.Executors;
 5
 6 import org.jboss.netty.bootstrap.ServerBootstrap;
 7 import org.jboss.netty.channel.ChannelFactory;
 8 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
 9
10 /**
11  * http服务启动类
12  *
13  * @author AlanLee
14  * @version 2018/01/11
15  *
16  */
17 public class HttpServer
18 {
19
20     public static void main(String[] args)
21     {
22         ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),
23                 Executors.newCachedThreadPool());
24         // 初始化channel的辅助类
25         ServerBootstrap bootstrap = new ServerBootstrap(factory);
26         bootstrap.setPipelineFactory(new ServerPipelineFactory());
27         // 创建服务器端channel的辅助类,接收connection请求
28         bootstrap.bind(new InetSocketAddress(8080));
29         System.out.println("Start http server success!");
30     }
31 }

Netty4实现Http协议服务接口步骤:

第一步:创建Http业务处理服务类,代码如下

 1 package com.alanlee.netty2;
 2
 3 import io.netty.buffer.ByteBuf;
 4 import io.netty.buffer.Unpooled;
 5 import io.netty.channel.ChannelHandlerContext;
 6 import io.netty.channel.SimpleChannelInboundHandler;
 7 import io.netty.handler.codec.http.DefaultFullHttpResponse;
 8 import io.netty.handler.codec.http.FullHttpRequest;
 9 import io.netty.handler.codec.http.HttpHeaderNames;
10 import io.netty.handler.codec.http.HttpHeaderValues;
11 import io.netty.handler.codec.http.HttpHeaders;
12 import io.netty.handler.codec.http.HttpResponseStatus;
13 import io.netty.handler.codec.http.HttpVersion;
14 import io.netty.util.AsciiString;
15
16 /**
17  * HttpServer业务处理
18  *
19  * @author AlanLee
20  * @version 2018/01/11
21  *
22  */
23 public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest>
24 {
25
26     private AsciiString contentType = HttpHeaderValues.TEXT_PLAIN;
27
28     @Override
29     protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception
30     {
31         String method = msg.method().name(); // 请求方式
32         String url = msg.uri().toLowerCase(); // 请求路径
33         System.out.println(method);
34         System.out.println(url);
35
36         // 接收请求内容并打印
37         ByteBuf byteBuf = msg.content();
38         byte[] bytes = new byte[byteBuf.readableBytes()];
39         byteBuf.readBytes(bytes);
40         String requestStr = new String(bytes, "UTF-8");
41         System.out.println(requestStr);
42
43         DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
44                 Unpooled.wrappedBuffer("你才是猪!".getBytes()));
45
46         HttpHeaders heads = response.headers();
47         // 返回内容的MIME类型
48         heads.add(HttpHeaderNames.CONTENT_TYPE, contentType + "; charset=UTF-8");
49         // 响应体的长度
50         heads.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
51         // 表示是否需要持久连接
52         heads.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
53
54         // 响应给客户端
55         ctx.write(response);
56     }
57
58     /**
59      * 数据发送完毕,则关闭连接通道.
60      */
61     @Override
62     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception
63     {
64         System.out.println("channelReadComplete");
65         super.channelReadComplete(ctx);
66         ctx.flush();
67     }
68
69     /**
70      * 发生异常
71      */
72     @Override
73     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
74     {
75         System.out.println("exceptionCaught");
76         if (null != cause)
77             cause.printStackTrace();
78         if (null != ctx)
79             ctx.close();
80     }
81
82 }

最后,让我们利用Netty4来发布Http协议服务接口,代码如下

 1 package com.alanlee.netty2;
 2
 3 import io.netty.bootstrap.ServerBootstrap;
 4 import io.netty.channel.ChannelInitializer;
 5 import io.netty.channel.ChannelOption;
 6 import io.netty.channel.nio.NioEventLoopGroup;
 7 import io.netty.channel.socket.SocketChannel;
 8 import io.netty.channel.socket.nio.NioServerSocketChannel;
 9 import io.netty.handler.codec.http.HttpObjectAggregator;
10 import io.netty.handler.codec.http.HttpRequestDecoder;
11 import io.netty.handler.codec.http.HttpResponseEncoder;
12
13 /**
14  * 搭建HttpServer
15  *
16  * @author Alanlee
17  * @version 2018/01/11
18  *
19  */
20 public class HttpServer
21 {
22
23     private final int port;
24
25     public HttpServer(int port)
26     {
27         this.port = port;
28     }
29
30     public static void main(String[] args) throws InterruptedException
31     {
32         new HttpServer(8081).start();
33         System.out.println("Start http server success!");
34     }
35
36     public void start() throws InterruptedException
37     {
38         // 初始化channel的辅助类
39         ServerBootstrap b = new ServerBootstrap();
40         NioEventLoopGroup group = new NioEventLoopGroup();
41         b.group(group).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>()
42         {
43             /**
44              * 初始化channel
45              */
46             @Override
47             protected void initChannel(SocketChannel ch) throws Exception
48             {
49                 System.out.println("initChannel ch:" + ch);
50                 // 获取管道
51                 ch.pipeline().addLast("decoder", new HttpRequestDecoder())  // 解码
52                         .addLast("encoder", new HttpResponseEncoder())      // 编码
53                         /* aggregator,消息聚合器(重要)。
54                         Netty4中为什么能有FullHttpRequest这个东西,
55                         就是因为有他,HttpObjectAggregator,如果没有他,
56                         就不会有那个消息是FullHttpRequest的那段Channel,
57                         同样也不会有FullHttpResponse,HttpObjectAggregator(512 * 1024)的参数含义是消息合并的数据大小,
58                         如此代表聚合的消息内容长度不超过512kb。*/
59                         .addLast("aggregator", new HttpObjectAggregator(512 * 1024))
60                         .addLast("handler", new HttpHandler()); // 请求的业务类
61             }
62
63         }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE);
64
65         // 创建服务器端channel的辅助类,接收connection请求
66         b.bind(port).sync();
67     }
68
69 }

检验成果

我们可以通过运行Netty3以及Netty4对应的HttpServer中的main方法来启动我们的Http服务器模拟。

启动Netty3提供的Http协议服务器,结果如下:

启动成功之后,我们利用Postman工具来做个简单的测试,注意这里Netty3使用的是8080端口,结果如下:

控制台输出内容如下:

我们再来启动Netty4提供的Http协议服务器,结果如下:

启动成功之后,我们利用Postman工具来做个简单的测试,注意这里Netty4使用的是8081端口,结果如下:

控制台输出内容如下:

这样,我们就成功的使用了Netty3和Netty4发布了Http协议服务接口,是不是很类似于我们的web后端开发,在平时的工作中如果遇到需要高并发的项目往往会需要将项目拆成后台节点来开发,此时可不仅仅web端需要提供接口,后台节点也是需要提供接口的,这是Netty就正好符合需求,所以大家可以花些时间去掌握Netty,建议掌握Netty4版本,这样版本升级的改动量会小很多,这里小Alan给大家开了扇门,把你引进门,修行在个人,如果你是一个热爱Java开发的人,也可以私聊Alan多多交流,只要Alan空闲的时候。

结束语:时间是最公平的,活一天就拥有24小时,差别只是珍惜。你若不相信努力和时光,时光一定第一个辜负你。有梦想就立刻行动,因为现在过的每一天,都是余生中最年轻的一天。

可爱博主:AlanLee

博客地址:http://www.cnblogs.com/AlanLee

原文地址:https://www.cnblogs.com/AlanLee/p/8270119.html

时间: 2024-10-15 22:13:58

使用Netty3或Netty4发布Http协议服务的相关文章

netty3升netty4一失眼成千古恨

老项目是netty3的,本来想直接改到netty5,但是netty5居然是只支持jdk1.7,很奇怪jdk1.6和jdk1.8都不行..为了兼容jdk1.6加上netty4本来和netty5就差别不大,最后上的netty4. 先期看了一些netty3升netty4的经验总结,然后开始动工.改完后运行一下,发现2个客户端连接,只有1个工作正常,另一个在建立连接的时候直接就阻塞到建立连接这里: channel = this.lastWriteFuture.awaitUninterruptibly()

Azure机器学习入门(四)模型发布为Web服务

接Azure机器学习(三)创建Azure机器学习实验,下一步便是真正地将Azure机器学习的预测模型发布为Web服务.要启用Web服务发布任务,首先点击底端导航栏的运行即"Run"按钮运行新的收入预测实验.实验开始运行之后,底端导航栏的发布Web服务即"Publish Web Service"按钮就变为有效,如下图所示. 图 即将发布Web服务地Azure 机器学习实验 此时,点击设计模式下底端导航栏的发布Web服务即"Publish Web Servic

自定义及发布一个webservice服务

自定义及发布一个webservice服务    - 声明 某个业务服务为webservice服务       通过@webservice 注解来声明    - 发布webservice服务       Endpoint.publish()发布 (默认对public修饰的方法进行发布)    - 通过wsimport生成本地代理来访问自己发布的webservice       wsimport 1.发布自定义webservice phone.java package ws.myWebService

java中发布一个webService服务到服务器

Java在编码完成webService服务端后,可以通过运行一个main方法来发布webService服务,但是实际将服务部署到服务器上后,肯定不能还运行main方法,所以我们需要在启动服务器的时候就发布服务.并且在服务器的生命周期内一直运行. main方法发布服务(可用于测试类) public static void main(String[] args) { Endpoint.publish("http://172.18.100.52:9090/medical", new Medi

arcgis server10.2.2发布地图基础服务的具体步骤

原文:arcgis server10.2.2发布地图基础服务的具体步骤 1.直接打开制作好的.mxd文档,比如这里: 2.打开mxd文档之后,打开菜单:file-share as -services 弹出地图发布服务的界面: 点击publish之后,耐心的等待一段时间,地图服务就发布好了,地图服务成功之后,可以在浏览器查看: (1) (2) (3) 到此地图服务发布结束! 备注: GIS技术交流QQ群:432512093

发布一个python服务框架iserver(带压力测试数据)

Iserver简介 Iserver是一个用python编写的网络服务框架(编译版本3.4.1),使用的是epool网络模型 测试机配置 处理器 2x Genuine Intel(R) CPU T2050 @ 1.60GHz 内存 2060MB (673MB used) nginx开启进程数 root 2413 2409 0 09:17 pts/0 00:00:00 grep -i nginx www 2414 2411 2 09:17 ? 00:00:00 nginx: worker proce

ArcGIS API for JavaScript(2)-ArcGIS Server发布要素图层服务

1.前言 上一篇该系列的文章我们主要讲了一下基础Web地图搭建,这篇我们主要讲一下ArcGIS Server发布服务,并且如何调用服务.将自己的数据加载到Web地图当中来,实现Web端浏览数据. 2.ArcGIS Server介绍与安装 1.ArcGIS Server 是功能强大的基于服务器的 GIS 产品,用于构建集中管理的.支持多用户的.具备高级GIS功能的企业级GIS应用与服务,如:空间数据管理.二维三维地图可视化.数据编辑.空间分析等即拿即用的应用和类型丰富的服务.ArcGIS Serv

java程序调用xfire发布的webService服务(二)

在上一篇的调用xfire发布的webService服务中,我只是从服务端返回了一个字符串给客户端,却没有测试从客户端传递数据给服务端.而实际应用中一般是不太可能只出现这样的应用场景的,因此我便更进一步测试了客户端传递数据给服务端. 因为相关的jar包在上一篇已经说过,因此便不再重复说明,这次的测试步骤如下: 一.测试向服务端传递字符串(重点在第二个): 为了进一步理解服务搭建,我重新写了一个服务端服务类: 接口: package xfireTest; public interface XFire

OpenLayers调用arcgis server发布的地图服务

有两种方式可以调用arcgis server发布的地图服务,一种是rest,一种是wms. 地图的投影为900913,arcgis server为10.0版本,地图服务的空间参考为3857. 与Google Map相对应的ArcGis投影文件: 众所周知,Google Map的投影参考为"WGS 84 Web墨卡托",定义为 EPSG:900913 或者 EPSG:3857 (EPSG:3785).与此相对应的ArcGis的投影坐标系名称为:WGS 1984 Web Mercator.