netty案例

最近在学习Netty,因为要学习网络通讯,所以在看完socket后,又接着看NIO,然后是Netty,可以说的是:先看完NIO,看完了NIO以后,再来看Netty,这样比较好懂一些,因为这里毕竟用到了Chanel,了解下NIO,对于熟悉Netty就会达到事半功倍的效果。

Netty是业界最流行的NIO框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的,它已经得到成百上千的商用项目验证,例如Hadoop的RPC框架avro使用Netty作为底层通信框架。很多其它业界主流的RPC框架,也使用Netty来构建高性能的异步通信能力。

通过对Netty的分析,我们将它的优点总结如下:

1)      API使用简单,开发门槛低;

2)      功能强大,预置了多种编解码功能,支持多种主流协议;

3)      定制能力强,可以通过ChannelHandler对通信框架进行灵活的扩展;

4)      性能高,通过与其它业界主流的NIO框架对比,Netty的综合性能最优;

5)      成熟、稳定,Netty修复了已经发现的所有JDK NIO BUG,业务开发人员不需要再为NIO的BUG而烦恼;

6)      社区活跃,版本迭代周期短,发现的BUG可以被及时修复,同时,更多的新功能会被加入;

7)      经历了大规模的商业应用考验,质量已经得到验证。在互联网、大数据、网络游戏、企业应用、电信软件等众多行业得到成功商用,证明了它可以完全满足不同行业的商业应用。

正是因为这些优点,Netty逐渐成为Java NIO编程的首选框架。


下面是一个小demo:

首先是pom.xml里的配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>sockets</groupId>
  <artifactId>socketDemo</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>socketDemo Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <!--Netty all-->
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.9.Final</version>
    </dependency>
      <!--Commons-codec -->
      <dependency>
          <groupId>commons-codec</groupId>
          <artifactId>commons-codec</artifactId>
          <version>1.10</version>
      </dependency>

      <!--dom4j-->
      <dependency>
          <groupId>dom4j</groupId>
          <artifactId>dom4j</artifactId>
          <version>1.6.1</version>
      </dependency>

      <!--fastjson-->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.33</version>
      </dependency>


      <!--log4j-->
      <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
      </dependency>

  </dependencies>
  <build>
    <finalName>socketDemo</finalName>
  </build>
</project>

第二,在resource里写一个配置文件 config.properties

#netty 服务端ip
nioServerIp=127.0.0.1
#netty 服务端端口
nioServerPort=19990

第三步,开始写代码了:

先写Service的Handler :serverHandler

package com.NEttydemo.test;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * Created by T430 on 2017/8/30.
 */

public class ServerHandler extends ChannelInboundHandlerAdapter {

    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("server received data:" + msg);
        ctx.write(msg);//写入数据
    }

    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)//flush调所有写回的数据
                .addListener(ChannelFutureListener.CLOSE);//当flash完成后关闭Channel
    }

    //重写了exceptionCaught方法,这里就是对当异常出现时的处理。
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();//捕获异常信息
        ctx.close();//出现异常时关闭channel
    }
}
在写server 

package com.NEttydemo.test;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

/**
 *
 * netty 服务器
 * Created by T430 on 2017/8/30.
 */
public class NettyServer {
    //IP地址
    private  static  String IP="127.0.0.1";
    //默认端口
    private  static  int port=5566;
    //组的数量
    private  static final  int BIZGROUPSIZE= Runtime.getRuntime().availableProcessors()*2;
    //头部数量
    private static final int BIZTHREADSIZE = 100;
    //创建领导组
    private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);
    //创建工作组
    private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);

    public static void init() throws  Exception{
        ServerBootstrap bootstrap=new ServerBootstrap();//声明 组
        bootstrap.group(bossGroup,workerGroup);//添加组

        bootstrap.channel(NioServerSocketChannel.class);//声明通道

        bootstrap.childHandler(new ChannelInitializer<Channel>() {
            protected void initChannel(Channel channel) throws Exception {
                // TODO Auto-generated method stub
                //pipeline管理channel中的Handler
                ChannelPipeline pipeline = channel.pipeline();
                pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                pipeline.addLast(new LengthFieldPrepender(4));
                pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
                pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
                pipeline.addLast(new ServerHandler());
            }
        });

        IP =Configuration.getProperty("nioServerIp");
        port=Integer.parseInt(Configuration.getProperty("nioServerPort"));
        System.out.println("【TCP服务器IP】"+IP+"【TCP服务器PORT】"+port);
        //配置完成,开始绑定server,通过调用sync同步方法阻塞直到绑定成功
        ChannelFuture f = bootstrap.bind(IP, port).sync();
        //应用程序会一直等待,直到channel关闭
        f.channel().closeFuture().sync();
        System.out.println("TCP服务器已启动");
    }

    protected static void shutdown() {
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

    public static void main(String[] args) throws Exception {
        System.out.println("初始化配置文件...");
        Configuration.init();
        System.out.println("开始启动TCP服务器...");
        NettyServer.init();
//         HelloServer.shutdown();
    }
}
接着写client的Handler  ClientHandler

package com.NEttydemo.test;


import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;


/**
 * Created by T430 on 2017/8/30.
 */

public class ClientHandler  extends ChannelInboundHandlerAdapter {


    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("【client接收到服务器返回的消息】:" + msg);
    }



    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("【client exception is general】");
    }
}

再写Client

package com.NEttydemo.test;


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;

import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;




/**
 *
 * 客户端
 * Created by T430 on 2017/8/30.
 */
public class NettyClient implements Runnable{

    public void run() {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group);
            b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                    pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                    pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                    pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));

                    pipeline.addLast("handler", new ClientHandler());
                }
            });

            ChannelFuture f = b.connect("127.0.0.1", 19990).sync();
            f.channel().writeAndFlush("Netty Hello Service!"+Thread.currentThread().getName()+":--->:"+Thread.currentThread().getId());
            f.channel().closeFuture().sync();



        } catch (Exception e) {

        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {

        for (int i = 0; i < 10; i++) {
            new Thread(new NettyClient(),"【this thread】 "+i).start();
        }
    }
}

最后得到的结果:

启动服务端的截图:


启动服务端,客户端后的截图分别是:








到此,demo结束!







猜你喜欢

转载自blog.csdn.net/qq_35357001/article/details/77715451