概述

保持客户端与服务器端连接的方案常用的有3种

1.长连接,也就是客户端与服务器端一直保持连接,适用于客户端比较少的情况。

2.定时段连接,比如在某一天的凌晨建立连接,适用于对实时性要求不高的情况。

3.设置连接超时,比如超过1分钟没有传输数据就断开连接,等下次需要的时候再建立连接,这种方案比较常用。

netty的ReadTimeOut实现方案3

服务端

大部分代码都保持不变,有变化的代码在第30行,设置服务端的超时时间

  1. import io.netty.bootstrap.ServerBootstrap;
  2. import io.netty.channel.ChannelFuture;
  3. import io.netty.channel.ChannelInitializer;
  4. import io.netty.channel.ChannelOption;
  5. import io.netty.channel.EventLoopGroup;
  6. import io.netty.channel.nio.NioEventLoopGroup;
  7. import io.netty.channel.socket.SocketChannel;
  8. import io.netty.channel.socket.nio.NioServerSocketChannel;
  9. import io.netty.handler.logging.LogLevel;
  10. import io.netty.handler.logging.LoggingHandler;
  11. import io.netty.handler.timeout.ReadTimeoutHandler;
  12.  
  13. public class Server {
  14.  
  15. public static void main(String[] args) throws Exception{
  16.  
  17. EventLoopGroup pGroup = new NioEventLoopGroup();
  18. EventLoopGroup cGroup = new NioEventLoopGroup();
  19.  
  20. ServerBootstrap b = new ServerBootstrap();
  21. b.group(pGroup, cGroup)
  22. .channel(NioServerSocketChannel.class)
  23. .option(ChannelOption.SO_BACKLOG, 1024)
  24. //设置日志
  25. .handler(new LoggingHandler(LogLevel.INFO))
  26. .childHandler(new ChannelInitializer<SocketChannel>() {
  27. protected void initChannel(SocketChannel sc) throws Exception {
  28. sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
  29. sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
  30. sc.pipeline().addLast(new ReadTimeoutHandler(5));
  31. sc.pipeline().addLast(new ServerHandler());
  32. }
  33. });
  34.  
  35. ChannelFuture cf = b.bind(8765).sync();
  36.  
  37. cf.channel().closeFuture().sync();
  38. pGroup.shutdownGracefully();
  39. cGroup.shutdownGracefully();
  40.  
  41. }
  42. }

ServerHandler代码也没有什么变化

  1. import io.netty.channel.ChannelHandlerAdapter;
  2. import io.netty.channel.ChannelHandlerContext;
  3.  
  4. public class ServerHandler extends ChannelHandlerAdapter{
  5.  
  6. @Override
  7. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  8.  
  9. }
  10.  
  11. @Override
  12. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  13. Request request = (Request)msg;
  14. System.out.println("Server : " + request.getId() + ", " + request.getName() + ", " + request.getRequestMessage());
  15. Response response = new Response();
  16. response.setId(request.getId());
  17. response.setName("response" + request.getId());
  18. response.setResponseMessage("响应内容" + request.getId());
  19. ctx.writeAndFlush(response);//.addListener(ChannelFutureListener.CLOSE);
  20. }
  21.  
  22. @Override
  23. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  24.  
  25. }
  26.  
  27. @Override
  28. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  29. ctx.close();
  30. }
  31.  
  32. }

客户端

客户端的代码也设置了超时时间(实际上只要服务器端设置也就可以了,有人说客户端不设置会出问题,现在还没有发现什么问题)。主要看getChannelFuture这个方法,this.cf == null是第一次连接的时候用到的,!this.cf.channel().isActive() 是连接超时后重新发起连接用到的。再看main方法,可以发现for(int i = 1; i <= 3; i++ ) 这个循环中,每个循环停顿4秒,也就是每隔4秒发送一次请求,而服务器端的超时时间设置为5秒,那么在这个for循环期间连接是不会断开的,等for循环结束 cf.channel().closeFuture().sync(); 断开连接this.cf.channel().isActive()  变为否,在new Thread()中再次发送请求,getChannelFuture会重新建立连接。

  1. import io.netty.bootstrap.Bootstrap;
  2. import io.netty.channel.ChannelFuture;
  3. import io.netty.channel.ChannelInitializer;
  4. import io.netty.channel.EventLoopGroup;
  5. import io.netty.channel.nio.NioEventLoopGroup;
  6. import io.netty.channel.socket.SocketChannel;
  7. import io.netty.channel.socket.nio.NioSocketChannel;
  8. import io.netty.handler.logging.LogLevel;
  9. import io.netty.handler.logging.LoggingHandler;
  10. import io.netty.handler.timeout.ReadTimeoutHandler;
  11.  
  12. import java.util.concurrent.TimeUnit;
  13.  
  14. /**
  15. * Best Do It
  16. */
  17. public class Client {
  18.  
  19. private static class SingletonHolder {
  20. static final Client instance = new Client();
  21. }
  22.  
  23. public static Client getInstance(){
  24. return SingletonHolder.instance;
  25. }
  26.  
  27. private EventLoopGroup group;
  28. private Bootstrap b;
  29. private ChannelFuture cf ;
  30.  
  31. private Client(){
  32. group = new NioEventLoopGroup();
  33. b = new Bootstrap();
  34. b.group(group)
  35. .channel(NioSocketChannel.class)
  36. .handler(new LoggingHandler(LogLevel.INFO))
  37. .handler(new ChannelInitializer<SocketChannel>() {
  38. @Override
  39. protected void initChannel(SocketChannel sc) throws Exception {
  40. sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
  41. sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
  42. //超时handler(当服务器端与客户端在指定时间以上没有任何进行通信,则会关闭响应的通道,主要为减小服务端资源占用)
  43. sc.pipeline().addLast(new ReadTimeoutHandler(5));
  44. sc.pipeline().addLast(new ClientHandler());
  45. }
  46. });
  47. }
  48.  
  49. public void connect(){
  50. try {
  51. this.cf = b.connect("127.0.0.1", 8765).sync();
  52. System.out.println("远程服务器已经连接, 可以进行数据交换..");
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. }
  56. }
  57.  
  58. public ChannelFuture getChannelFuture(){
  59.  
  60. if(this.cf == null){
  61. this.connect();
  62. }
  63. if(!this.cf.channel().isActive()){
  64. this.connect();
  65. }
  66.  
  67. return this.cf;
  68. }
  69.  
  70. public static void main(String[] args) throws Exception{
  71. final Client c = Client.getInstance();
  72. //c.connect();
  73.  
  74. ChannelFuture cf = c.getChannelFuture();
  75. for(int i = 1; i <= 3; i++ ){
  76. Request request = new Request();
  77. request.setId("" + i);
  78. request.setName("pro" + i);
  79. request.setRequestMessage("数据信息" + i);
  80. cf.channel().writeAndFlush(request);
  81. TimeUnit.SECONDS.sleep(4);
  82. }
  83.  
  84. cf.channel().closeFuture().sync();
  85.  
  86. new Thread(new Runnable() {
  87. @Override
  88. public void run() {
  89. try {
  90. System.out.println("进入子线程...");
  91. ChannelFuture cf = c.getChannelFuture();
  92. System.out.println(cf.channel().isActive());
  93. System.out.println(cf.channel().isOpen());
  94.  
  95. //再次发送数据
  96. Request request = new Request();
  97. request.setId("" + 4);
  98. request.setName("pro" + 4);
  99. request.setRequestMessage("数据信息" + 4);
  100. cf.channel().writeAndFlush(request);
  101. cf.channel().closeFuture().sync();
  102. System.out.println("子线程结束.");
  103. } catch (InterruptedException e) {
  104. e.printStackTrace();
  105. }
  106. }
  107. }).start();
  108.  
  109. System.out.println("断开连接,主线程结束..");
  110.  
  111. }
  112.  
  113. }

clientHandler没有什么变化

  1. import io.netty.channel.ChannelHandlerAdapter;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.util.ReferenceCountUtil;
  4.  
  5. public class ClientHandler extends ChannelHandlerAdapter{
  6.  
  7. @Override
  8. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  9.  
  10. }
  11.  
  12. @Override
  13. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  14. try {
  15. Response resp = (Response)msg;
  16. System.out.println("Client : " + resp.getId() + ", " + resp.getName() + ", " + resp.getResponseMessage());
  17. } finally {
  18. ReferenceCountUtil.release(msg);
  19. }
  20. }
  21.  
  22. @Override
  23. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  24.  
  25. }
  26.  
  27. @Override
  28. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  29. ctx.close();
  30. }
  31.  
  32. }

工厂类不变

  1. import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;
  2. import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;
  3. import io.netty.handler.codec.marshalling.MarshallerProvider;
  4. import io.netty.handler.codec.marshalling.MarshallingDecoder;
  5. import io.netty.handler.codec.marshalling.MarshallingEncoder;
  6. import io.netty.handler.codec.marshalling.UnmarshallerProvider;
  7.  
  8. import org.jboss.marshalling.MarshallerFactory;
  9. import org.jboss.marshalling.Marshalling;
  10. import org.jboss.marshalling.MarshallingConfiguration;
  11.  
  12. /**
  13. * Marshalling工厂
  14. * @author(alienware)
  15. * @since 2014-12-16
  16. */
  17. public final class MarshallingCodeCFactory {
  18.  
  19. /**
  20. * 创建Jboss Marshalling解码器MarshallingDecoder
  21. * @return MarshallingDecoder
  22. */
  23. public static MarshallingDecoder buildMarshallingDecoder() {
  24. //首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
  25. final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
  26. //创建了MarshallingConfiguration对象,配置了版本号为5
  27. final MarshallingConfiguration configuration = new MarshallingConfiguration();
  28. configuration.setVersion(5);
  29. //根据marshallerFactory和configuration创建provider
  30. UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
  31. //构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
  32. MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024);
  33. return decoder;
  34. }
  35.  
  36. /**
  37. * 创建Jboss Marshalling编码器MarshallingEncoder
  38. * @return MarshallingEncoder
  39. */
  40. public static MarshallingEncoder buildMarshallingEncoder() {
  41. final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
  42. final MarshallingConfiguration configuration = new MarshallingConfiguration();
  43. configuration.setVersion(5);
  44. MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
  45. //构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
  46. MarshallingEncoder encoder = new MarshallingEncoder(provider);
  47. return encoder;
  48. }
  49. }

自定义的Request和Response对象没有什么变化,这里不再赘述

架构师养成记--22.客户端与服务器端保持连接的解决方案,netty的ReadTimeoutHandler的更多相关文章

  1. 架构师养成记--35.redis集群搭建

    前记:redis哨兵经验之谈.哨兵做主从切换可能要花费一两秒,这一两秒可能会丢失很多数据.解决方法之一是在java代码中做控制,try catch 到 链接断开的异常就sleep 一两秒钟再conti ...

  2. 架构师养成记--21.netty编码解码

    背景 作为网络传输框架,免不了哟啊传输对象,对象在传输之前就要序列化,这个序列化的过程就是编码过程.接收到编码后的数据就需要解码,还原传输的数据. 代码 工厂类 import io.netty.han ...

  3. 架构师养成记--19.netty

    一.Netty初步 为什么选择Netty? 和NIO比较,要实现一个通信要简单得很多,性能很好.分布式消息中间件.storm.Dubble都是使用Netty作为底层通信. Netty5.0要求jdk1 ...

  4. 架构师养成记--9.future模式讲解

    什么是future模式呢?解释这个概念之前我们先来了解一个场景吧,财务系统的结账功能,这个功能可能是每个月用一次,在这一个月中相关的数据量已经积累得非常大,这一个功能需要调用好几个存储过程来完成.假如 ...

  5. 架构师养成记--30.Redis环境搭建

    Redis的安装 下载地址http://redis.io/download 安装步骤: 首先需要安装gcc,把下载好的redis-3.0.0-rc2.tar.gz 放到 /usr/local 文件夹下 ...

  6. 架构师养成记--20.netty的tcp拆包粘包问题

    问题描述 比如要发ABC DEFG HIJK 这一串数据,其中ABC是一个包,DEFG是一个包,HIJK是一个包.由于TCP是基于流发送的,所以有可能出现ABCD EFGH 这种情况,那么ABC和D就 ...

  7. 架构师养成记--18.NIO

    有人叫new IO 我这里就叫Non-block IO 经典概念: Buffer(缓冲区):之前直接通过流,现在提供一个buffer存放数据. Channel:管道,包括ServerSocketCha ...

  8. 架构师养成记--15.Disruptor并发框架

    一.概述 disruptor对于处理并发任务很擅长,曾有人测过,一个线程里1s内可以处理六百万个订单,性能相当感人. 这个框架的结构大概是:数据生产端 --> 缓存 --> 消费端 缓存中 ...

  9. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

随机推荐

  1. 修改数据库的instance_name和db_name

    分成两个步骤,先修改instance_name,在修改db_name 修改SID1.全备份数据库RMAN> backup as compressed backupset database inc ...

  2. 优化 resolv.conf

    DNS lookup 在把域名解析成 IP 过程中耽误了不少时间,尤其是访问比较复杂的网站的时候,比如某个页面包含多个 url,一次请求需要做多次 DNS 解析,并且从用户浏览器到 DNS serve ...

  3. java常量池与对象存储

    一 数据存储位置                                 我们先来谈谈数据的存储位置,有五个地方可以存储数据 (1)寄存器:这是最快的存储区,因为它位于不同于其他存储区的地方- ...

  4. 一些json在js和c++ jsoncpp的操作

    1.对于javascript部分,如果将字符串转为json对象? var aa ={ keyword:"zoumm", requestcount:"5", ne ...

  5. 图灵社区 书单推荐:成为Java顶尖程序员 ,看这11本书就够了

    java书单推荐 转自 http://www.ituring.com.cn/article/211418 “学习的最好途径就是看书“,这是我自己学习并且小有了一定的积累之后的第一体会.个人认为看书有两 ...

  6. jdbc注册驱动 class.forName()

    从源码 D:\Javasoftware\MySql\mysql\mysql-connector-java-5.1.7\src\com\mysql\jdbc\Driver.java class.forN ...

  7. python 命令行工具 fire

    简介 A library for automatically generating command line interfaces. Python Fire is a library for auto ...

  8. linux上chrome、vlc等程序root不能运行的解决办法

    which vlc 或者 whereis vlc 输入/geteuid,输入i进入输入模式,将geteuid改成getppid,然后ESC,输入wq,保存退出,这样程序root用户就可以运行了. ch ...

  9. RocketMQ runbroker.sh 分析JVM启动参数

    runbroker.sh #====================================================================================== ...

  10. nancyfx中的静态内容文件夹

    原文件 DefaultStaticContentsConventions.cs 可以根据需要自定调整,在代码里改的好处是通用.如果通过在webconfig里设置的话,在非iis环境下,可能会有问题. ...