本节介绍TIME协议。该协议与前边的discard协议和echo协议的不同点在于:
1、服务端主动发送消息给到客户端,所以需要channelActive()方法。
2、发送的消息是4个字节的int
3、不接收来自客户端的任何请求,所以不需要channelRead()方法。
4、一旦消息发送完毕,就关闭该connection。

一、server端

TimeServerHandler.java

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TimeServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {//(1)final ByteBuf time = ctx.alloc().buffer(4);//(2)time.writeInt((int)(System.currentTimeMillis()/1000L+2208988800L));log.info("{}",(int)(System.currentTimeMillis()/1000L+2208988800L));final ChannelFuture f = ctx.writeAndFlush(time);//(3)f.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) throws Exception {assert f == future;ctx.close();}});//(4)
    }@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}}

1、当客户端与服务端建立了connection时,立即触发服务端的channelActive()方法。该方法内写一个4个字节的int,用于表示当前时间。
2、分配一个4字节的buffer,来存储int。采用ChannelHandlerContext.alloc()获取当前的ByteBufAllocator,来分配一个新的buffer。
3、先说下,java.nio.flip():调用flip()以后,读/写指针position知道缓冲区头部,并设置了最多能读出的已写入数据长度(不是buffer的capacity)。
那这里的NIO,为啥在发送消息之前,不调用flip()呢?因为netty中的ByteBuf没有该方法。为啥没有?因为,ByteBuf有2个指针;一个是read另一个是write。当你调用buffer.writeXXX(...)时,write index会增加,而read index不变。反之,当你buffer.readXXX()时,read index会增加,而write index不变。read index代表buffer的当前未读的位置(没read过,就是0,read了1个字节就是1),而write index代表以后写入的位置(可读字节的结束位置)。
另外,在注意一点,ChannelHandlerContext.write(和writeAndFlush())方法返回ChannelFuture。该ChannelFuture代表着异步,意味着write或writeAndFlush不会立即执行。例如:下边的代码可能会先执行close()然后在执行writeAndFlush

Channel ch = ...;
ch.writeAndFlush(message);
ch.close();

因此,应该在ChannelFuture完成后,写close()方法。当write完成后会ChannelFuture会通知其listeners。

4、那我们该怎么写呢?很简单,为该返回的ChannelFuture增加一个ChannelFutureListener。

f.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) throws Exception {assert f == future;ctx.close();}
});

这里,我们创建了一个匿名的ChannelFutureListener来关闭该Channel,当write完成后。另外一种方法是,可简化写成预定义的:

f.addListener(ChannelFutureListener.CLOSE);

TimeServer.java,可以拷贝之前的DiscardServer.java,将添加的handler改成TimeServerHandler即可。

不管用哪种方法,close()方法可能不会立即关闭connection,他会返回一个ChannelFuture

二、客户端

因为int类型的时间戳,看不懂,只能借助程序翻译,因此,不像DISCARD和ECHO server可以不需要client。本节介绍编写client。client与server的最大且唯一的不同在于Bootstrap和Channel的实现类不同。
server:使用ServerBootstrap、NioServerSocketChannel
client:使用Bootstrap、NioSocketChannel
发现:server中的都带server,client中均去掉了server。

TimeClient.java

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TimeClient {public static void main(String[] args) throws Exception {String host = "localhost";int port = 8080;EventLoopGroup workerGroup = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();//(1)b.group(workerGroup);//(2)b.channel(NioSocketChannel.class);//(3)b.option(ChannelOption.SO_KEEPALIVE, true);//(4)b.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new TimeClientHandler());}});//start the client.ChannelFuture f = b.connect(host,port).sync();//(5)//wait until the connection is closed.
            f.channel().closeFuture().sync();log.info("client channel is closed.");} finally {workerGroup.shutdownGracefully();}}}

1、Bootstrap类似ServerBootstrap,但其只能应用于客户端或者无连接通信下的channel,例如:UDP,可实现在预先不建立连接的情况下,实现广播。
2、如果只声明了一个EventLoopGroup,那么该group既作为boss group又作为worker group。
3、客户端使用NioSocketChannel,服务端使用NioServerSocketChannel。
4、客户端中没有childOption()。
5、客户端中使用connect()而不是使用bind()方法。

如你所见,客户端与服务端的启动代码并无多大区别。下边写handler,来接收4字节整数,翻译为可读格式的日期,最后关闭connection。

TimeClientHandler.java

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.date.DateUtil;
@Slf4j
public class TimeClientHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf m = (ByteBuf) msg;try {long currentTimeMillis = (m.readUnsignedInt() - 2208988800L)*1000L;log.info("{}",DateUtil.date(currentTimeMillis));ctx.close();} finally {m.release();//(1)
        }}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}}

1、因为不用了(不传递给其他handler,因为没有),所以释放掉。

测试结果:
客户端:

22:09:03.324 [nioEventLoopGroup-2-1] 2018-09-12 22:09:03
22:09:03.437 [main] client channel is closed.

服务端:

22:09:03.276 [nioEventLoopGroup-3-1] -549217153

说明:本例有时会抛出IndexOutOfBoundsException异常,将在下一节讨论。

转载于:https://www.cnblogs.com/yaoyuan2/p/9630965.html

Netty(3)Time protocol相关推荐

  1. Objective-C 入门(七)协议 protocol(JAVA中的接口)

    Objective-C 入门(七)协议 protocol(JAVA中的接口) 接口的作用想必大家都比较了解 OV中的 protocol 相比接口作用相似 语法稍有不同 1.先来看声明一个协议 在创建文 ...

  2. Netty(一)——Netty入门程序

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7447618.html 有兴趣的可先了解下:4种I/O的对比与选型 主要内容包括: Netty开发环境的搭建 ...

  3. Netty(二)——TCP粘包/拆包

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7814644.html 前面讲到:Netty(一)--Netty入门程序 主要内容: TCP粘包/拆包的基础知 ...

  4. 从BIO到Netty(1)- Linux网络模型简介

    从BIO到Netty(1)- Linux网络模型简介 前言 Linux网络模型简介 阻塞I/O 非阻塞I/O I/O复用模型 信号驱动I/O 异步I/O 总结 参考资料 前言 其实我一直以来都有做笔记 ...

  5. 深入分析netty(一)BootStrap与ServerBootStrap

    文章目录 1.揭开BootStrap神秘面纱 1.1.客户端BootStrap 1.1.1 NioSocketChannel 的初始化过程 1.1.2 ChannelFactory 和Channel类 ...

  6. 从tcp到netty(一)

    发现自己近一年有些毛病,自己也算是研习了不少的源代码,看了不少的技术书籍,但是自己就是记忆力不行,总是过段时间就会忘记,忘记之后还得从头开始啃源码.啃书籍.而且有些重要技术点也会遗忘,导致再学习的时候 ...

  7. Spring - Netty (整合)

      写在前面  ​ 大家好,我是作者尼恩.目前和几个小伙伴一起,组织了一个高并发的实战社群[疯狂创客圈].正在开始 高并发.亿级流程的 IM 聊天程序 学习和实战,此文是:   疯狂创客圈 Java ...

  8. Java基础之《netty(28)—TCP粘包拆包原理》

    一.基本介绍 1.TCP是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(Na ...

  9. Netty(一)基础socketchannel,Buffer,selector黏包 半包解决 实战

    NIO 基础 non-blockiong io:非阻塞 阻塞vs非阻塞 三大组件 1.channel & Buffer channel : 双向流 Buffer:暂存数据 缓冲区 常见chan ...

  10. Netty(三)文件上传下载、心跳检测

    文件上传 Http服务 //http服务 public final class HttpServer {static final boolean SSL = System.getProperty(&q ...

最新文章

  1. ipone 网页版的iphone
  2. Windows消息:WM_USER与WM_APP的区别
  3. Linux服务-Samba文件服务器部署
  4. 每日一笑 | 我写了一段代码,为什么不能运行呢?
  5. 微软Silverlight,你应该知道的10件事
  6. Golang笔记—封装/继承/接口
  7. 智能会议系统---(4)VOIP 实现
  8. 一加7T Pro曝光:10月10日发布
  9. 支付宝最不想看到的:当“集五福”变成赚钱生意 有人日入千元!
  10. coreboot学习6:ramstage阶段之芯片初始化流程
  11. 【POJ2676】Sudoku(优化搜索顺序)
  12. Hive利用正则Serde导入文件
  13. android 用platform.x509.pem platform.pk8对apk进行签名
  14. C#调用PB生成dll详解
  15. 英语思维导图大全 介词(七)
  16. VNC实现Windows远程访问Ubuntu 16.04(转)
  17. win7系统 邮箱服务器搭建,win7搭建邮箱服务器
  18. RNA-seq的典型流程(protocol)
  19. sci写作之前的记录
  20. 电脑无法连接mysql_本地电脑无法连接到MySQL

热门文章

  1. CentOS 7 重装mysql编译过程报错解决方法
  2. MongoDB数据库导出导入迁移
  3. 从零实现爬虫和情感分类模型(二)
  4. 【经验之谈】掌握这13个PyTorch Trick,让你做实验行云流水~
  5. 【笔记】双线性池化(Bilinear Pooling)详解、改进及应用
  6. 数据结构与算法python—7.链表题目leetcode总结
  7. SpringCloud——服务调用
  8. 深度学习花书-5.4 估计、偏差和方差
  9. 那些Python意想不到的对象
  10. 敏捷无它,唯持续改进