一,服务端

**
 * 测试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. [零基础学JAVA]Java SE基础部分-04. 分支、循环语句

    转自:http://redking.blog.51cto.com/27212/116751 1.课程名称:分支.循环 本季为JAVA程序中最重要的部分,在讲解的时候除了讲解各种主要的控制语句(分支语句 ...

  2. App上线流程全攻略(史上最具体步骤)

    @转载请保留:iOS界一迷糊小书童--->专注于iOS开发!!谢谢合作 /*****************************************1****************** ...

  3. IE11,Chrome65,Firefox58 的webdriver驱动下载,调用浏览器打开网址

    一.环境及需求 1.1环境 Windows10 + Python 3.6.4 + selenium 3.141 1.2需求 工作需要实现一个网页自动登录的操作,决定使用selenium+python实 ...

  4. PHP------文件------文件整体操作

    文件整体操作 [1]创建文件 touch("路径");   touch("./test.docx");//当前路径创建文件,创建的文档 显示的结果: touch ...

  5. wampserver 最新版本 mysql修改数据库密码

    由于wampsever版本更新就导致以前版本的密码修改造成失败,主要是密码字段改变造成的! 第一步 进入MySQL 控制台  wamp安装,数据库是没有密码 进入控制台直接回车就可以了 第二步 使用 ...

  6. Spring(十九)之异常处理

    异常处理,对于项目开发至关重要,总不能用户点击一个页面出错了,直接报500,那样用户体验多不好啊! 所以这里讲的是SpringMVC对异常的处理,希望能给大家带来一定的 帮助和启发. 一.编写实体 p ...

  7. 【题解】洛谷P2704 [NOI2001] 炮兵阵地(状压DP)

    洛谷P2704:https://www.luogu.org/problemnew/show/P2704 思路 这道题一开始以为是什么基于状压的高端算法 没想到只是一道加了一行状态判断的状压DP而已 与 ...

  8. 小程序OSS图片上传

    图片上传加水印问题,代码如下! chooseImage: function (e) { var that = this; wx.chooseImage({ sizeType: ['original', ...

  9. C++ ACM基础

    一.C++结构体 #include <iostream> using namespace std; struct Point{ int x; int y; Point(int x=0,in ...

  10. 通过xshell在linux上安装mysql5.7(终极版)

    通过xshell在linux上安装mysql5.7(终极版) 0)通过xshell连接到远程服务器 1)彻底删除原来安装的mysql 首先查看:rpm -qa|grep -i mysql 删除操作(一 ...