一,服务端

**
 * 测试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. Service Fabric eShop On Containers

    Service Fabric承载eShop On Containers 从模块化到微服务化 从Pet Shop 到eShop on Container都是Microsoft在技术演进的路径上给开发者展 ...

  2. linux自动备份oracle数据库

    #此脚本只备份数据表,而且为了方便恢复数据是做的单表逐个备份#在写脚本过程中遇到的报错均加入了解决方案的链接(虽然错误代码没有贴出来)#最终将在脚本所在目录生成年月日-时分的目录,目录下为表名.dmp ...

  3. 解决Ubuntu启动错误——kernel panic not syncing vfs unable to mount root fs on unknown-block 0 0 – error

    最近在倒腾Ubuntu,然后想着怎么美化一下界面,于是照着网上的教程整了一下Flatabulous这个软件,然后好像/boot就满了.关机之后再开机就出现了如题所述的错误,无法开机,也无法进入reco ...

  4. Django 按时间来查找数据库中的数据

    问题: 按时间来查找数据表中的数据. 前提: 1. 数据表student中有一个字段类型为DateField或者DateTimeField字段, 字段名是birthday. 2. 数据表中已经有些数据 ...

  5. Ubuntu16.04死机解决方案

    内核下载地址:http://kernel.ubuntu.com/~kernel-ppa/mainline/ Ubuntu 16.04 LTS,电源设置里面的休眠/挂起/睡眠功能会使电脑会进入死机状态, ...

  6. 面试准备——(二)专业知识(1)Linux

    面试的问题: 腾讯: 1. 查看进程的命令 美团: 1. 常用的命令——美团/滴滴 2. 如何在性能测试的时候查看进程 3. kill -9/-15区别 滴滴: 1.如何找到一个特定文件 2. 如何替 ...

  7. Vue教程:过滤器filters(五)

    Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化.过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持).过滤器应该被添加在 JavaScrip ...

  8. iOS之动态计算文字的高度

    + (CGSize)boundingALLRectWithSize:(NSString *)txt Font:(UIFont *)font Size:(CGSize)size { NSMutableA ...

  9. Android 微信页面刷新问题

    今天测试妹纸提了个bug,Android手机用微信打开测试页面,刷新功能无效.因为开发时懒,只验证了Ios手机无异常,没有注意打安卓这个问题. 我是直接用的window.location.reload ...

  10. ziplist之详细分析

    压缩列表ziplist ziplist是一种连续,无序的数据结构.压缩列表是 Redis 为了节约内存而开发的, 由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结构. 组成 属性 ...