专栏首页猿天地高性能NIO框架Netty入门篇

高性能NIO框架Netty入门篇

Netty介绍

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

也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

官网地址:http://netty.io/

使用场景

Netty之所以能成为主流的NIO框架,是因为它有下面的优点:

  1. NIO的类库和API使用难度较高,Netty进行了封装,容易上手
  2. 高性能,功能强大,支持多种编解码功能,支持多种主流协议
  3. 成熟,稳定,已经在多个大型框架中使用(dubbo,RocketMQ,Hadoop,mycat,Spring5)
  4. …..

在几年之前我上家公司用的是Mina来开发一个IM的系统,Mina也是一个很好的框架(http://mina.apache.org/)。 如今很多的框架都改成用Netty来做底层通讯了,我司现在还有一个代理框架用Mina写的,等把Netty玩遛了可以重构了。

不知道大家看完了上面的介绍是不是已经知道Netty能用在什么场景了,下面我结合一个我之前做过的事情来进行详细的说明,当然只是使用场景的一方面而已。

之前做抓取的时候,有一些小型的网站,页面结构比较复杂,还需要登录等操作,这种就不能用统一的抓取系统去抓取,只能通过写脚本的方式针对具体的网站做抓取,抓取必备的一个条件就是代理IP,为了方便抓取,特意封装了一个抓取的SDK,提供了抓取的方法,内置了切换代理。

我们有一个代理池服务,通过一个网址去获取能使用的代理IP,在刚开始用的Http请求去获取代理IP,由于抓取量比较大,通过Http请求去获取代理IP效率不行,后面用Netty改造了获取IP这部分,通过Netty来获取数据,解决了实时获取的性能问题。

通过长连接的方式,避免了Http请求每次都要建立连接带来的性能消耗问题,通过二进制的数据传输减少网络开销,性能更高。

简单入门

我们编写一个服务端和客户端,客户端往服务端发送一条消息,消息传输先用字符串进行传递,服务端收到客户端发送的消息,然后回复一条消息。

首先编写服务端代码:

public class ImServer {
    public void run(int port) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() { 
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast("decoder", new StringDecoder());
                        ch.pipeline().addLast("encoder", new StringEncoder());
                        ch.pipeline().addLast(new ServerStringHandler());
                    }
                })
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        try {
            ChannelFuture f = bootstrap.bind(port).sync();
             f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
  1. 通过ServerBootstrap 进行服务的配置,和socket的参数可以通过ServerBootstrap进行设置。
  2. 通过group方法关联了两个线程组,NioEventLoopGroup是用来处理I/O操作的线程池,第一个称为“boss”,用来accept客户端连接,第二个称为“worker”,处理客户端数据的读写操作。当然你也可以只用一个NioEventLoopGroup同时来处理连接和读写,bootstrap.group()方法支持一个参数。
  3. channel指定NIO方式
  4. childHandler用来配置具体的数据处理方式 ,可以指定编解码器,处理数据的Handler
  5. 绑定端口启动服务

消息处理:

/**
 * 消息处理
 * @author yinjihuan
 *
 */
public class ServerStringHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.err.println("server:" + msg.toString());
        ctx.writeAndFlush(msg.toString() + "你好");
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

启动服务,指定端口为2222:

public static void main(String[] args) {
    int port = 2222;
    new Thread(() -> {
        new ImServer().run(port);
    }).start();
}

编写客户端连接逻辑:

public class ImConnection {
    private Channel channel;
    public Channel connect(String host, int port) {
        doConnect(host, port);
        return this.channel;
    }
    private void doConnect(String host, int port) {
        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 {    
                    ch.pipeline().addLast("decoder", new StringDecoder());
                    ch.pipeline().addLast("encoder", new StringEncoder());
                    ch.pipeline().addLast(new ClientStringHandler());
                }
            });
            ChannelFuture f = b.connect(host, port).sync();
            channel = f.channel();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

客户端消息处理:

/**
 * 当编解码器为字符串时用来接收数据
 * @author yinjihuan
 *
 */
public class ClientStringHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("client:" + msg.toString());
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

客户端启动入口,然后发送消息给服务端:

public static void main(String[] args) {
    String host = "127.0.0.1";
    int port = 2222;
    Channel channel = new ImConnection().connect(host, port);
    channel.writeAndFlush("yinjihuan");
}

测试步骤如下:

  1. 首先启动服务端
  2. 启动客户端,发送消息
  3. 服务端收到消息,控制台有输出server:yinjihuan
  4. 客户端收到服务端回复的消息,控制台有输出client:yinjihuan你好

源码参考:https://github.com/yinjihuan/netty-im

本文分享自微信公众号 - 猿天地(cxytiandi),作者:尹吉欢

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-03-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Netty4自带编解码器详解

    前言 本篇文章是Netty专题的第五篇,前面四篇文章如下: 高性能NIO框架Netty入门篇 高性能NIO框架Netty-对象传输 高性能NIO框架Netty-...

    猿天地
  • 高性能NIO框架Netty-对象传输

    上篇文章高性能NIO框架Netty入门篇我们对Netty做了一个简单的介绍,并且写了一个入门的Demo,客户端往服务端发送一个字符串的消息,服务端回复一个字符串...

    猿天地
  • Java开源框架中的设计模式以及应用场景

    设计模式是软件设计中常见问题的典型解决方案,你可以通过对其进行定制来解决代码中的特定设计问题。

    猿天地
  • Netty 如何实现心跳机制与断线重连?

    所谓心跳, 即在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性.

    范蠡
  • Netty 如何实现心跳机制与断线重连?

    所谓心跳, 即在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性.

    Java技术栈
  • 使用Identity Server 4建立Authorization Server (1)

    本文内容基本完全来自于Identity Server 4官方文档: https://identityserver4.readthedocs.io/ 官方文档很详...

    solenovex
  • 二分查找(python)

    假期无聊,在家无网络,就看了看传说中的算法,一个字难 下面都是本人的愚见,如有不对请谅解: 二分查找的前提是有序其次是排除一半,比如1..100之间猜一个数值...

    零月
  • .NET Core中使用Razor模板引擎

     在MVC以外的场景中,我们往往需要完成一些模板引擎生成代码或页面的工作;在以前我们一般常用的有Razor、NVeocity、VTemplate。虽然所有的模...

    yoyofx
  • EXT.NET高效开发(一)——概述

    之前就有想法说说这方面,直到看到我上一篇博客《EXT.NET复杂布局(一)——工作台》的回复:

    雪雁-心莱科技
  • 分布式任务调度系统xxl-job源码探究(一、客户端)

    老梁

扫码关注云+社区

领取腾讯云代金券