一 初遇Netty

Netty是什么?

Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能、可扩展协议的服务器和客户端。

Netty能做什么?

Netty 是一个 NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器(HTTP服务器,FTP服务器,WebSocket服务器,Redis的Proxy服务器等等)和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。

Netty为什么好?

Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象,使用它你可以更容易利用Java NIO提高服务端和客户端的性能。

Netty的特性

1. 设计

  1. 1.1 统一的API,适用于不同的协议(阻塞和非阻塞)
  2. 1.2 基于可扩展和灵活的事件驱动模型
  3. 1.3高度可定制的线程模型 - 单线程,一个或多个线程池,如SEDA
  4. 1.4真正的无连接数据报套接字支持(自3.1以来)

2. 性能

  1. 2.1更好的吞吐量,低延迟
  2. 2.2更省资源
  3. 2.3尽量减少不必要的内存拷贝

3. 安全

  1. 完整的SSL / TLSStartTLS协议的支持

4. 易用性

  1. 4.1 官方有详细的使用指南
  2. 4.2 对环境要求很低

NIO和IO的区别是什么?

1. 一个面向字节一个面向缓冲;

IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

2. NIO是非阻塞IO,IO是阻塞IO

阻塞意味着当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入,该线程在此期间不能再干任何事情了。而非阻塞不会这样。

二 Netty使用

环境要求:

- JDK 7+

- Maven 3.2.x

- Netty 4.x

Maven依赖:

  1. <dependency>
  2. <groupId>io.netty</groupId>
  3. <artifactId>netty-all</artifactId>
  4. <version>4.0.32.Final</version>
  5. </dependency>

以下Netty examples来源: 官方文档

2.1 写个抛弃服务器

DiscardServerHandler.java

  1. import io.netty.buffer.ByteBuf;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.ChannelInboundHandlerAdapter;
  4. /**
  5. * handler 是由 Netty 生成用来处理 I/O 事件的。
  6. */
  7. public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)
  8. /**
  9. * 这里我们覆盖了 chanelRead() 事件处理方法。
  10. * 每当从客户端收到新的数据时,这个方法会在收到消息时被调用。
  11. *((ByteBuf) msg).release():丢弃数据
  12. */
  13. @Override
  14. public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
  15. // 默默地丢弃收到的数据
  16. ((ByteBuf) msg).release(); // (3)
  17. }
  18. @Override
  19. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
  20. // 当出现异常就关闭连接
  21. cause.printStackTrace();
  22. ctx.close();
  23. }
  24. }

目前我们已经实现了 DISCARD 服务器的一半功能,剩下的需要编写一个 main() 方法来启动服务端的 DiscardServerHandler。

DiscardServer.java

  1. import io.netty.bootstrap.ServerBootstrap;
  2. import io.netty.channel.ChannelFuture;
  3. import io.netty.channel.ChannelInitializer;
  4. import io.netty.channel.ChannelOption;
  5. import io.netty.channel.EventLoopGroup;
  6. import io.netty.channel.nio.NioEventLoopGroup;
  7. import io.netty.channel.socket.SocketChannel;
  8. import io.netty.channel.socket.nio.NioServerSocketChannel;
  9. /**
  10. * 启动服务端的 DiscardServerHandler
  11. */
  12. public class DiscardServer {
  13. private int port;
  14. public DiscardServer(int port) {
  15. this.port = port;
  16. }
  17. public void run() throws Exception {
  18. //在这个例子中我们实现了一个服务端的应用,因此会有2个 NioEventLoopGroup 会被使用。
  19. //第一个经常被叫做‘boss’,用来接收进来的连接。
  20. //第二个经常被叫做‘worker’,用来处理已经被接收的连接,一旦‘boss’接收到连接,就会把连接信息注册到‘worker’上。
  21. EventLoopGroup bossGroup = new NioEventLoopGroup();
  22. EventLoopGroup workerGroup = new NioEventLoopGroup();
  23. try {
  24. //启动 NIO 服务的辅助启动类
  25. ServerBootstrap serverBootstrap = new ServerBootstrap();
  26. //用于处理ServerChannel和Channel的所有事件和IO。
  27. serverBootstrap.group(bossGroup, workerGroup)
  28. .channel(NioServerSocketChannel.class) // (3)
  29. .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
  30. @Override
  31. public void initChannel(SocketChannel ch) throws Exception {
  32. ch.pipeline().addLast(new DiscardServerHandler());
  33. }
  34. })
  35. .option(ChannelOption.SO_BACKLOG, 128) // (5)
  36. .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
  37. // 绑定端口,开始接收进来的连接
  38. ChannelFuture f = serverBootstrap.bind(port).sync(); // (7)
  39. // 等待服务器 socket 关闭 。
  40. // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  41. f.channel().closeFuture().sync();
  42. } finally {
  43. workerGroup.shutdownGracefully();
  44. bossGroup.shutdownGracefully();
  45. }
  46. }
  47. public static void main(String[] args) throws Exception {
  48. int port;
  49. if (args.length > 0) {
  50. port = Integer.parseInt(args[0]);
  51. } else {
  52. port = 8080;
  53. }
  54. new DiscardServer(port).run();
  55. }
  56. }

2.2 查看收到的数据

我们刚刚已经编写出我们第一个服务端,我们需要测试一下他是否真的可以运行。最简单的测试方法是用 telnet 命令。例如,你可以在命令行上输入telnet localhost 8080 或者其他类型参数。

然而我们能说这个服务端是正常运行了吗?事实上我们也不知道,因为他是一个 discard 服务,你根本不可能得到任何的响应。为了证明他仍然是在正常工作的,让我们修改服务端的程序来打印出他到底接收到了什么。

我们已经知道 channelRead() 方法是在数据被接收的时候调用。让我们放一些代码到 DiscardServerHandler 类的 channelRead() 方法。

修改DiscardServerHandler类的channelRead(ChannelHandlerContext ctx, Object msg)方法如下:

  1. @Override
  2. public void channelRead(ChannelHandlerContext ctx, Object msg) {
  3. ByteBuf in = (ByteBuf) msg;
  4. try {
  5. while (in.isReadable()) { // (1)
  6. System.out.print((char) in.readByte());
  7. System.out.flush();
  8. }
  9. } finally {
  10. ReferenceCountUtil.release(msg); // (2)
  11. }
  12. }

再次验证,cmd下输入:telnet localhost 8080。你将会看到服务端打印出了他所接收到的消息。

如下:

你在dos界面输入的消息会被显示出来

2.3 写个应答服务器

到目前为止,我们虽然接收到了数据,但没有做任何的响应。然而一个服务端通常会对一个请求作出响应。让我们学习怎样在 ECHO 协议的实现下编写一个响应消息给客户端,这个协议针对任何接收的数据都会返回一个响应。

和 discard server 唯一不同的是把在此之前我们实现的 channelRead() 方法,返回所有的数据替代打印接收数据到控制台上的逻辑。因此,需要把 channelRead() 方法修改如下:

  1. @Override
  2. public void channelRead(ChannelHandlerContext ctx, Object msg) {
  3. ctx.write(msg);
  4. ctx.flush();
  5. }

再次验证,cmd下输入:telnet localhost 8080。你会看到服务端会发回一个你已经发送的消息。

如下:

下一篇我们会学习如何用Netty实现聊天功能。

欢迎关注我的微信公众号(分享各种Java学习资源,面试题,以及企业级Java实战项目回复关键字免费领取):

网络应用框架Netty快速入门的更多相关文章

  1. Nodejs ORM框架Sequelize快速入门

    Nodejs ORM框架Sequelize快速入门 什么是ORM? 简单的讲就是对SQL查询语句的封装,让我们可以用OOP的方式操作数据库,优雅的生成安全.可维护的SQL代码.直观上,是一种Model ...

  2. Mybatis框架 的快速入门

    MyBatis 简介 什么是 MyBatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果 ...

  3. [jbdj]SpringMVC框架(1)快速入门

    1)springmvc快速入门(传统版) 步一:创建springmvc_demo一个web应用 步二:导入springioc,springweb , springmvc相关的jar包 步三:在/WEB ...

  4. ssm框架整合快速入门

    写在前面: 公司一直都是使用ssh框架(Struts2,Spring,Hibernate)来开发,但是现在外面的公司大多数都是使用的ssm框架,所以也有必要多学习一下外面的新技术.这里就快速搭建一个小 ...

  5. Hibernate入门第一讲——Hibernate框架的快速入门

    Hibernate框架的概述 什么是框架? 框架指的是软件的半成品,已经完成了部分功能. JavaEE开发的三层架构 了解框架的基本概念之后,我们就来看看Hibernate框架处于JavaEE开发的经 ...

  6. Netty快速入门(01)Linux I/O模型介绍

    Netty简述 Netty是一个高性能的网络编程框架. 上面提到了几个关键的字眼,高性能,网络编程,框架.这些概括Netty的本质. Netty是一个NIO客户端服务器框架,可以快速轻松地开发协议服务 ...

  7. Netty快速入门(06)Netty介绍

    前面简单的介绍了Java I/O 和NIO,写了示例程序. Java I/O是阻塞的,为了让它支持多个并发,就要针对每个链接启动线程,这种方式的结果就是在海量链接的情况下,会创建海量的线程,就算用线程 ...

  8. 分布式应用框架Akka快速入门

    转自:http://blog.csdn.net/jmppok/article/details/17264495 本文结合网上一些资料,对他们进行整理,摘选和翻译而成,对Akka进行简要的说明.引用资料 ...

  9. Shiro安全框架【快速入门】就这一篇!

    Shiro 简介 照例又去官网扒了扒介绍: Apache Shiro™ is a powerful and easy-to-use Java security framework that perfo ...

随机推荐

  1. bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】

    //========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/  转载要声明! //=============== ...

  2. POJ1474:Video Surveillance——题解

    http://poj.org/problem?id=1474 题目大意:给按照顺时针序的多边形顶点,问其是否有内核. —————————————————————————————— (和上道题目一模一样 ...

  3. POJ1149:PIGS——题解

    http://poj.org/problem?id=1149 题目大意: Mirko有M个猪圈和N个客户,猪圈里有特定数量的猪,每个客户按照顺序来买猪,他们只能打开他们能打开的猪圈,然后取走一些猪(上 ...

  4. BZOJ4698 & 洛谷2463:[SDOI2008]Sandy的卡片——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=4698 https://www.luogu.org/problemnew/show/P2463#sub ...

  5. HDU4825:Xor Sum——题解

    http://acm.hdu.edu.cn/showproblem.php?pid=4825 Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含 ...

  6. redux connect的浅比较说明

    redux的connect方法是一个高阶组件,对包装的组件会在ShouldComponentUpdate中实现一个默认的浅比较. connect形式如下: connect([mapStateToPro ...

  7. Poco::URI

    #include<iostream> #include<typeinfo> #include<Poco/Path.h> #include <Poco/Dire ...

  8. 在Linux中新增与删除用户可以使用命令:Useradd

    在Linux中新增与删除用户可以使用命令:Useradd 我们先使用man命令理解一下Useradd的用法 新增与删除用户操作需要先获取高级用户权限 输入命令:sudo -i 确定后输入高级用户密码 ...

  9. switch语法的盲点

    switch语法在项目使用的频率很低,今天看到一个相关的例子引发一些思考,,同时自己也写了一些简单的例子如下: 实例1: int dayOfWeek = 5; switch (dayOfWeek){ ...

  10. 平衡二叉树 (牛客国庆day2)解锁二叉树打表姿势&&找规律套路

    链接:https://www.nowcoder.com/acm/contest/202/F来源:牛客网 平衡二叉树,顾名思义就是一棵“平衡”的二叉树.在这道题中,“平衡”的定义为,对于树中任意一个节点 ...