一,服务端

**
 * 测试Netty类库:服务端代码
 * Created by LiuHuiChao on 2016/10/24.
 */
public class NettyServerTest {
    private int port;
    public NettyServerTest(int port){
        this.port=port;
    }

    /**
     * EventLoopGroup 是用来处理I/O操作的多线程事件循环器,
     * Netty提供了许多不同的EventLoopGroup的实现用来处理不同传输协议。
     *
     *
     * @throws Exception
     */
    public void run() throws Exception{
        //一旦 boss 接收到连接,就会把连接信息注册到worker上面
        EventLoopGroup bossGroup=new NioEventLoopGroup();//用来接收进来的连接
        EventLoopGroup workerGroup=new NioEventLoopGroup();//用来处理已经被接收的连接

        System.out.println("准备运行端口:"+port);
        try{
            //ServerBootstrap是一个启动NIO服务的辅助启动类,可以在这个服务中直接使用CChannel
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            serverBootstrap=serverBootstrap.group(bossGroup,workerGroup);//这一步是必须的
            serverBootstrap=serverBootstrap.channel(NioServerSocketChannel.class);
            /*
            * 这里的事件处理类经常会被用来处理一个最近的已经接收的Channel。
                              * ChannelInitializer是一个特殊的处理类,
                                * 他的目的是帮助使用者配置一个新的Channel。
                               * 也许你想通过增加一些处理类比如NettyServerHandler来配置一个新的Channel
                               * 或者其对应的ChannelPipeline来实现你的网络程序。
                               * 当你的程序变的复杂时,可能你会增加更多的处理类到pipline上,
                                * 然后提取这些匿名类到最顶层的类上。
              */
            serverBootstrap=serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //socketChannel.pipeline().addLast(new DiscardServerHandler());
                    socketChannel.pipeline().addLast(new TimeServerHandler());
                }
            });
            /**
             * 可以设置这里指定的通道实现配置参数
             * 我们正在写一个TCP/IP的服务端
             * 因此我们被允许设置socket的参数选项比如tcpNoDelay,keepAlive
             */
            serverBootstrap=serverBootstrap.option(ChannelOption.SO_BACKLOG,128);
            serverBootstrap=serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);
            /**
             * 绑定端口并启动区接收进来的连接
             */
            ChannelFuture f=serverBootstrap.bind(port).sync();
            f.channel().closeFuture().sync();//这里会一直等待,知道socket被关闭
           }catch (Exception e){

        }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=8088;
        }
        new NettyServerTest(port).run();
    }

}

/**
 * Created by LiuHuiChao on 2016/10/24.
 */
public class TimeServerHandler  extends ChannelHandlerAdapter {

    /**
     * 为了发送一个新的消息,我们需要分配一个包含这个消息的新的缓冲。
     * 因为我们需要写入一个32位的整数,因此我们需要一个至少有4个字节的ByteBuf。
     * 通过ChannelHandlerContext.alloc()得到一个当前的ByteBufAllocator,
     * 然后分配一个新的缓冲。
     */
    @Override
    public void channelActive(final ChannelHandlerContext ctx) throws Exception {
        final ByteBuf time=ctx.alloc().buffer(4);
        time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));

        /***
         * 和往常一样我们需要编写一个构建好的消息
         * 。但是等一等,flip在哪?难道我们使用NIO发送消息时不是调用java.nio.ByteBuffer.flip()吗?
         * ByteBuf之所以没有这个方法因为有两个指针,
         * 一个对应读操作一个对应写操作。
         * 当你向ByteBuf里写入数据的时候写指针的索引就会增加,
         * 同时读指针的索引没有变化。
         * 读指针索引和写指针索引分别代表了消息的开始和结束。
         * 比较起来,NIO缓冲并没有提供一种简洁的方式来计算出消息内容的开始和结尾,
         * 除非你调用flip方法。
         * 当你忘记调用flip方法而引起没有数据或者错误数据被发送时,
         * 你会陷入困境。这样的一个错误不会发生在Netty上,
         * 因为我们对于不同的操作类型有不同的指针。
         * 你会发现这样的使用方法会让你过程变得更加的容易,
         * 因为你已经习惯一种没有使用flip的方式。
         * 另外一个点需要注意的是ChannelHandlerContext.write()(和writeAndFlush())方法会返回一个ChannelFuture对象,
         * 一个ChannelFuture代表了一个还没有发生的I/O操作。
         * 这意味着任何一个请求操作都不会马上被执行,
         * 因为在Netty里所有的操作都是异步的。
         * 因此你需要在write()方法返回的ChannelFuture完成后调用close()方法,
         * 然后当他的写操作已经完成他会通知他的监听者。
         */
        final ChannelFuture f=ctx.writeAndFlush(time);

        /**
         * 当一个写请求已经完成是如何通知到我们?
         * 这个只需要简单地在返回的ChannelFuture上增加一个ChannelFutureListener。
         * 这里我们构建了一个匿名的ChannelFutureListener类用来在操作完成时关闭Channel。
         */
        f.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                assert f==channelFuture;
                ctx.close();//close方法也可能不会里面关闭,会返回一个ChannelFuture
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

二,客户端

/**
 * Created by LiuHuiChao on 2016/10/24.
 */
public class TimeClient {
    public static void main(String[] args) throws Exception {
        String host="127.0.0.1";
        int port=8088;
        EventLoopGroup workerGroup=new NioEventLoopGroup();
        try{
            /**
             * 如果只指定了一个EventLoopGroup,
             * 那它就会作为boss线程,也会作为worker线程
             * 尽管客户端不需要boss线程
             */
            Bootstrap b=new Bootstrap();
            b.group(workerGroup);
            /**
             * 代替NioServerSocketChannel的是NioSocketChannel,这个类在客户端channel被创建时候调用
             */
            b.channel(NioSocketChannel.class);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new TimeClientHandler());
                }
            });
            ChannelFuture f=b.connect(host,port).sync();//用connect方法替代bind方法
            f.channel().closeFuture().sync();//等到运行结束,关闭
        }finally {
            workerGroup.shutdownGracefully();
        }
    }
}

/**
 * Created by LiuHuiChao on 2016/10/24.
 */
public class TimeClientHandler  extends ChannelHandlerAdapter {
    private ByteBuf buf;

    /**
     * 开始处理的时候触发
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        buf=ctx.alloc().buffer(4);//分配4个字节的空间给ByteBuf
    }

    /**
     * 处理结束的时候触发
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        buf.release();//释放ByteBuf的空间
        buf=null;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf m=(ByteBuf) msg;
        buf.writeBytes(m);
        m.release();
        if(buf.readableBytes()>=4){
            long currentTimeMillis=(buf.readInt() - 2208988800L) * 1000L;
            System.out.println(new Date(currentTimeMillis));
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

(⊙o⊙)…先跑跑。。有点儿困了

Netty示例的更多相关文章

  1. netty 入门二 (传输bytebuf 或者pojo)

    基于流的数据传输:在基于流的传输(如TCP / IP)中,接收的数据被存储到套接字接收缓冲器中. 不幸的是,基于流的传输的缓冲区不是数据包的队列,而是字节队列. 这意味着,即使您将两个消息作为两个独立 ...

  2. Netty 核心组件 EventLoop 源码解析

    前言 在前文 Netty 启动过程源码分析 (本文超长慎读)(基于4.1.23) 中,我们分析了整个服务器端的启动过程.在那篇文章中,我们重点关注了启动过程,而在启动过程中对核心组件并没有进行详细介绍 ...

  3. Netty 入门初体验

    Netty简介 Netty是一款异步的事件驱动的网络应用程序框架,支持快速开发可维护的高性能的面向协议的服务器和客户端.Netty主要是对java 的 nio包进行的封装 为什么要使用 Netty 上 ...

  4. Netty快速入门(10)Reactor与Netty

    Reactor模式 Reactor是1995年由道格拉斯提出的一种高性能网络编程模式.由于好多年了,当时的一些概念与现在略有不同,reactor模式在网络编程中是非常重要的,可以说是NIO框架的典型模 ...

  5. netty 4.x用户使用指南

    引言 问题 现在我们使用通用的应用程序或库来相互通信.例如,我们经常使用HTTP客户机从web服务器检索信息,并通过web服务调用远程过程调用.然而,通用协议或其实现有时不能很好地进行扩展.这就像我们 ...

  6. Netty之旅二:口口相传的高性能Netty到底是什么?

    高清思维导图原件(xmind/pdf/jpg)可以关注公众号:一枝花算不算浪漫 回复netty01即可. 前言 上一篇文章讲了NIO相关的知识点,相比于传统IO,NIO已经做得很优雅了,为什么我们还要 ...

  7. 深入了解Netty【六】Netty工作原理

    引言 前面学习了NIO与零拷贝.IO多路复用模型.Reactor主从模型. 服务器基于IO模型管理连接,获取输入数据,又基于线程模型,处理请求. 下面来学习Netty的具体应用. 1.Netty线程模 ...

  8. 网络编程Netty入门:Netty的启动过程分析

    目录 Netty的启动过程 Bootstrap 服务端的启动 客户端的启动 TCP粘包.拆包 图示 简单的例子 Netty编解码框架 Netty解码器 ByteToMessageDecoder实现类 ...

  9. Netty4.x中文教程系列(三) Hello World !详解

    Netty 中文教程 (二) Hello World !详解 上一篇文章,笔者提供了一个Hello World 的Netty示例. 时间过去了这么久,准备解释一下示例代码. 1.HelloServer ...

随机推荐

  1. hdu 4825 Xor Sum(trie+贪心)

    hdu 4825 Xor Sum(trie+贪心) 刚刚补了前天的CF的D题再做这题感觉轻松了许多.简直一个模子啊...跑树上异或x最大值.贪心地让某位的值与x对应位的值不同即可. #include ...

  2. Mysql分表和分区的区别、分库分表介绍与区别(转)

    分表和分区的区别: 一,什么是mysql分表,分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看:mysql分表的3种方法 什么是分区,分区呢就是把一张表的数据分成N多个区块,这 ...

  3. 对HandlerExecutionChain类的理解分析

    HandlerExecutionChain类比较简单,好理解. ==================================================================== ...

  4. Linux硬盘扩容

    1.安装gparted分区工具 2.从虚拟机设置新的虚拟硬盘 3.挂载分区 sudo mount -t ext4 /dev/sdb1 /home/zhoushuo/zsdf -hsudo chmod ...

  5. reactnative 原生组件通信原理

    http://www.csdn.net/article/2015-11-27/2826345-compare-React-Native-with-ExMobi 原生组件通信原理 React Nativ ...

  6. UVA11987 【Almost Union-Find】

    这是一道神奇的题目,我调了大概一天多吧 首先hack一下翻译,操作3并没有要求查询后从其所在集合里删除该元素 于是我们来看一下这三个操作 第一个合并属于并查集的常规操作 第三个操作加权并查集也是可以解 ...

  7. js 实现图片无限横向滚动效果

    门户网站好多都有产品无线滚动展现的效果: 测试demo1 -- 非无缝滚动(可以看出来从头开始的效果): css样式如下: .box{ width: 1000px; border: 1px solid ...

  8. HDU 1019 (多个数的最小公倍数)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1019 Least Common Multiple Time Limit: 2000/1000 MS (J ...

  9. C# Console类的方法使用总结

    Console类表示控制台应用程序的标准输入流.输出流和错误流. 此类不能被继承,而在Java中,类似的功能则由System.in和System.out来实现了. 一 输出到控制台 输出到控制台就是把 ...

  10. 『ACM C++』 PTA 天梯赛练习集L1 | 042-43

    记录刷题情况 ------------------------------------------------L1-042--------------------------------------- ...