一,服务端

**
 * 测试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. css3实现 两个点之间有一条线,循环运动

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  2. servlet api.jar是干什么的?

    支持servlet的jar包.应该叫servlet-api.jar你如果编写过servlet就知道要用到HttpServletRequest和HttpServletResponse等对象,这些对象都是 ...

  3. 哈哈,原来IOC容器的bean是存在DefaultSingletonBeanRegistry的一个Map类型的属性当中。

    经过查看源代码发现IOC容器中的bean实例(不知道是不是所有的bean)是存储在一个DefaultSingletonBeanRegistry类实例的一个Map类型的属性当中. 下面是DefaultS ...

  4. IO流输入输出流,字符字节流

    一.流 1.流的概念 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作. ...

  5. 高老大 ‘SQL Server 优化器特性导致的内存授予相关BUG’ 学习笔记

    今天高老大出了好文章.在这里 自己本来对这一块比较混乱,正好借这个机会学习一下. 就用高老大的脚本.需要的直接去他那里找吧,这里就省了. 加查询优化标记前后对比 可以看到GrantedMemory是5 ...

  6. selenium基础知识(概述、安装、IDE等)

    参考http://www.yiibai.com/selenium/selenium_webdriver.html

  7. c#返回值的理解

    我感觉没什么用...就是在别的地方用的时候可以直接以Add(a,b)这样的方式赋值就行,不用再用c这个中间变量去接收了,希望有一天有大佬能给我讲讲设置返回值有什么好处

  8. C#的常用类

    BitConverter类:用于将源类型转换成字节数组,或者将字节数组转换成目标类型.在解决不同设备之间产生的大小端问题时,经常使用. Convert类:用于基本数据类型(包括Boolean/Byte ...

  9. Spark Streaming编程示例

    近期也有开始研究使用spark streaming来实现流式处理.本文以流式计算word count为例,简单描述如何进行spark streaming编程. 1. 依赖的jar包 参考<分别用 ...

  10. oracle系列(二)用户管理

    SQL> conn /as sysdbaConnected to Oracle Database 11g Express Edition Release 11.2.0.2.0 Connected ...