网络应用框架Netty快速入门
2018-04-05 00:00
483 查看
摘要: Netty 是一个 NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器(HTTP服务器,FTP服务器,WebSocket服务器,Redis的Proxy服务器等等)和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。
<font color="#6666CC">Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能、可扩展协议的服务器和客户端。</font>
<font color="#33CC33" size="4"> Netty能做什么?</font>
<font color="#6666CC">Netty 是一个 NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器(HTTP服务器,FTP服务器,WebSocket服务器,Redis的Proxy服务器等等)和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。</font>
<font color="#33CC33" size="4"> Netty为什么好?</font>
<font color="#6666CC">Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象,使用它你可以更容易利用Java NIO提高服务端和客户端的性能。</font>
Netty的特性:
<font color="#99CCCC"> 1. 设计</font>
<font color="#99CCCC">2. 性能</font>
<font color="#99CCCC">3. 安全</font>
<font color="#99CCCC">4. 易用性</font>
<font color="#33CC33" size="4"> NIO和IO的区别是什么?</font>
<font color="#99CCCC">1. 一个面向字节一个面向缓冲;</font>
IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的
3ff0
数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
<font color="#99CCCC">2. NIO是非阻塞IO,IO是阻塞IO</font>
阻塞意味着当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入,该线程在此期间不能再干任何事情了。而非阻塞不会这样。
JDK 7+
Maven 3.2.x
Netty 4.x
Maven依赖:
以下Netty examples来源: 官方文档
目前我们已经实现了 DISCARD 服务器的一半功能,剩下的需要编写一个 main() 方法来启动服务端的 DiscardServerHandler。
<font color="#99CCCC">DiscardServer.java</font>
然而我们能说这个服务端是正常运行了吗?事实上我们也不知道,因为他是一个 discard 服务,你根本不可能得到任何的响应。为了证明他仍然是在正常工作的,让我们修改服务端的程序来打印出他到底接收到了什么。
我们已经知道 channelRead() 方法是在数据被接收的时候调用。让我们放一些代码到 DiscardServerHandler 类的 channelRead() 方法。
<font color="#99CCCC">修改DiscardServerHandler类的channelRead(ChannelHandlerContext ctx, Object msg)方法如下:</font>
再次验证,cmd下输入:telnet localhost 8080。你将会看到服务端打印出了他所接收到的消息。
如下:
你在dos界面输入的消息会被显示出来
和 discard server 唯一不同的是把在此之前我们实现的 channelRead() 方法,返回所有的数据替代打印接收数据到控制台上的逻辑。因此,需要把 channelRead() 方法修改如下:
再次验证,cmd下输入:telnet localhost 8080。你会看到服务端会发回一个你已经发送的消息。
如下:
下一篇我们会学习如何用Netty实现聊天功能。
欢迎关注我的微信公众号:"Java 面试通关手册"(坚持原创,分享美文,分享各种Java学习资源,面试题,以及企业级Java实战项目回复关键字免费领取):
一 初遇Netty
<font color="#33CC33" size="4"> Netty是什么?</font><font color="#6666CC">Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能、可扩展协议的服务器和客户端。</font>
<font color="#33CC33" size="4"> Netty能做什么?</font>
<font color="#6666CC">Netty 是一个 NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器(HTTP服务器,FTP服务器,WebSocket服务器,Redis的Proxy服务器等等)和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。</font>
<font color="#33CC33" size="4"> Netty为什么好?</font>
<font color="#6666CC">Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象,使用它你可以更容易利用Java NIO提高服务端和客户端的性能。</font>
Netty的特性:
<font color="#99CCCC"> 1. 设计</font>
1.1 统一的API,适用于不同的协议(阻塞和非阻塞) 1.2 基于可扩展和灵活的事件驱动模型 1.3高度可定制的线程模型 - 单线程,一个或多个线程池,如SEDA 1.4真正的无连接数据报套接字支持(自3.1以来)
<font color="#99CCCC">2. 性能</font>
2.1更好的吞吐量,低延迟 2.2更省资源 2.3尽量减少不必要的内存拷贝
<font color="#99CCCC">3. 安全</font>
完整的SSL / TLS和StartTLS协议的支持
<font color="#99CCCC">4. 易用性</font>
4.1 官方有详细的使用指南 4.2 对环境要求很低
<font color="#33CC33" size="4"> NIO和IO的区别是什么?</font>
<font color="#99CCCC">1. 一个面向字节一个面向缓冲;</font>
IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的
3ff0
数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
<font color="#99CCCC">2. NIO是非阻塞IO,IO是阻塞IO</font>
阻塞意味着当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入,该线程在此期间不能再干任何事情了。而非阻塞不会这样。
二 Netty使用
环境要求:JDK 7+
Maven 3.2.x
Netty 4.x
Maven依赖:
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.0.32.Final</version> </dependency>
以下Netty examples来源: 官方文档
2.1 写个抛弃服务器
<font color="#99CCCC">DiscardServerHandler.java</font>import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; /** * handler 是由 Netty 生成用来处理 I/O 事件的。 */ public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1) /** * 这里我们覆盖了 chanelRead() 事件处理方法。 * 每当从客户端收到新的数据时,这个方法会在收到消息时被调用。 *((ByteBuf) msg).release():丢弃数据 */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2) // 默默地丢弃收到的数据 ((ByteBuf) msg).release(); // (3) } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4) // 当出现异常就关闭连接 cause.printStackTrace(); ctx.close(); } }
目前我们已经实现了 DISCARD 服务器的一半功能,剩下的需要编写一个 main() 方法来启动服务端的 DiscardServerHandler。
<font color="#99CCCC">DiscardServer.java</font>
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; /** * 启动服务端的 DiscardServerHandler */ public class DiscardServer { private int port; public DiscardServer(int port) { this.port = port; } public void run() throws Exception { //在这个例子中我们实现了一个服务端的应用,因此会有2个 NioEventLoopGroup 会被使用。 //第一个经常被叫做‘boss’,用来接收进来的连接。 //第二个经常被叫做‘worker’,用来处理已经被接收的连接,一旦‘boss’接收到连接,就会把连接信息注册到‘worker’上。 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //启动 NIO 服务的辅助启动类 ServerBootstrap serverBootstrap = new ServerBootstrap(); //用于处理ServerChannel和Channel的所有事件和IO。 serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // (3) .childHandler(new ChannelInitializer<SocketChannel>() { // (4) @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new DiscardServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) // (5) .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) // 绑定端口,开始接收进来的连接 ChannelFuture f = serverBootstrap.bind(port).sync(); // (7) // 等待服务器 socket 关闭 。 // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new DiscardServer(port).run(); } }
2.2 查看收到的数据
我们刚刚已经编写出我们第一个服务端,我们需要测试一下他是否真的可以运行。最简单的测试方法是用 telnet 命令。例如,你可以在命令行上输入telnet localhost 8080 或者其他类型参数。然而我们能说这个服务端是正常运行了吗?事实上我们也不知道,因为他是一个 discard 服务,你根本不可能得到任何的响应。为了证明他仍然是在正常工作的,让我们修改服务端的程序来打印出他到底接收到了什么。
我们已经知道 channelRead() 方法是在数据被接收的时候调用。让我们放一些代码到 DiscardServerHandler 类的 channelRead() 方法。
<font color="#99CCCC">修改DiscardServerHandler类的channelRead(ChannelHandlerContext ctx, Object msg)方法如下:</font>
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf in = (ByteBuf) msg; try { while (in.isReadable()) { // (1) System.out.print((char) in.readByte()); System.out.flush(); } } finally { ReferenceCountUtil.release(msg); // (2) } }
再次验证,cmd下输入:telnet localhost 8080。你将会看到服务端打印出了他所接收到的消息。
如下:
你在dos界面输入的消息会被显示出来
2.3 写个应答服务器
到目前为止,我们虽然接收到了数据,但没有做任何的响应。然而一个服务端通常会对一个请求作出响应。让我们学习怎样在 ECHO 协议的实现下编写一个响应消息给客户端,这个协议针对任何接收的数据都会返回一个响应。和 discard server 唯一不同的是把在此之前我们实现的 channelRead() 方法,返回所有的数据替代打印接收数据到控制台上的逻辑。因此,需要把 channelRead() 方法修改如下:
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ctx.write(msg); ctx.flush(); }
再次验证,cmd下输入:telnet localhost 8080。你会看到服务端会发回一个你已经发送的消息。
如下:
下一篇我们会学习如何用Netty实现聊天功能。
欢迎关注我的微信公众号:"Java 面试通关手册"(坚持原创,分享美文,分享各种Java学习资源,面试题,以及企业级Java实战项目回复关键字免费领取):
相关文章推荐
- 网络应用框架Netty快速入门
- NHibernate的基本使用、快速入门 - Microsoft.NET开发框架应用资源(zhuan)
- netty vs mina网络应用编程框架
- 使用 Android快速开发框架 Afinal 0.3 快速开发网络应用相关APK
- 分布式应用框架Akka快速入门
- Java网络应用框架Mina和Netty初步接触笔记
- 快速开发基于 HTML5 网络拓扑图应用--入门篇(一)
- 分布式应用框架Akka快速入门
- Quartz 框架快速入门(三)--应用到WEB项目中
- 快速入门过程与方法:设计与思路;如何学习新的知识框架,建立思维模式,熟悉应用场景体系
- 快速开发基于 HTML5 网络拓扑图应用--入门篇(二)
- 分布式应用框架Akka快速入门
- 分布式应用框架Akka快速入门
- 【转载】Gradle学习 第十章:网络应用快速入门
- 分布式应用框架Akka快速入门
- 分布式应用框架Akka快速入门
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V1 -- 入门应用
- 分布式应用框架Akka快速入门
- Netty logo 高性能网络应用框架 Netty
- 快速开发基于 HTML5 网络拓扑图应用--入门篇(一)