##

Netty实战 IM即时通讯系统(五)客户端启动流程

零、 目录

  1. IM系统简介
  • Netty 简介
  • Netty 环境配置
  • 服务端启动流程
  • 实战: 客户端和服务端双向通信
  • 数据传输载体ByteBuf介绍
  • 客户端与服务端通信协议编解码
  • 实现客户端登录
  • 实现客户端与服务端收发消息
  • pipeline与channelHandler
  • 构建客户端与服务端pipeline
  • 拆包粘包理论与解决方案
  • channelHandler的生命周期
  • 使用channelHandler的热插拔实现客户端身份校验
  • 客户端互聊原理与实现
  • 群聊的发起与通知
  • 群聊的成员管理(加入与退出,获取成员列表)
  • 群聊消息的收发及Netty性能优化
  • 心跳与空闲检测
  • 总结
  • 扩展

五、 客户端启动流程

  1. 客户端启动demo

     /*** 客户端启动流程* */public class Test_05_客户端启动流程 {public static void main(String[] args) {NioEventLoopGroup workerGroup = new NioEventLoopGroup();Bootstrap bootstrap = new Bootstrap();bootstrap// 指定线程模型.group(workerGroup)// 指定IO 模型.channel(NioSocketChannel.class)// 指定业务处理逻辑.handler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {}});// 建立连接bootstrap.connect("127.0.0.1" , 8000).addListener(future ->{if(future.isSuccess()) {System.out.println("连接成功");}else {System.out.println("连接失败");}});}}
    
    1. 从上面的代码可以看出 , 客户端的启动引导类是BootStrap , 负责启动客户端以及连接服务端 , 而上面一小节我们在描述服务端启动的时候, 这个引导类是 ServerBootStrap , 引导类创建完成之后我们描述一下客户端启动流程:

      1. 首先和服务端的启动流程一样 , 我们需要给特指定线程模型, 驱动着连接的数据读写
      2. 然后我们指定IO 模型为 NioSocketChannel , 表示IO模型为 NIO
      3. 接着, 我们给引导类指定一个handler , 这里主要就是定义连接的业务处理逻辑 , 不理解没有关系 , 我们在后面会详解
      4. 配置完线程模型 , IO 模型 , 业务处理逻辑之后 , 调用connect() 方法进行连接 , 可以看到connect() 方法有两个参数 , 第一个参数可以填写IP或域名 ,第二个参数填写的是端口号 , 由于connect() 方法返回的是一个Future , 也就是说这个方法是异步的 , 我们通过addListener方法可以监听到连接是否成功 , 进而打印连接状态
    2. 到这里一个客户端的demo 就完成了 , 其实只要和客户端Socket 编程模型对应起来 , 这里的三个概念就会显得非常简单
  2. 失败重连

    1. 在网络差的情况下 , 客户端第一次连接可能会失败 , 这个时候我们可能会尝试重新连接 , 重新连接的逻辑写在连接失败的逻辑块里

       // 建立连接bootstrap.connect("127.0.0.1" , 8000).addListener(future ->{if(future.isSuccess()) {System.out.println("连接成功");}else {System.out.println("连接失败");//TODO: 重新连接逻辑}});
      
    2. 重新连接时依然是调用相同的逻辑 , 所以我们把连接的代码抽取出来, 实现代码复用 , 在连接失败的情况下使用递归的方法 实现重连

       public static void connect(Bootstrap bootstrap, String IP, int port) {// 建立连接bootstrap.connect(IP, port).addListener(future -> {if (future.isSuccess()) {System.out.println("连接成功");} else {System.out.println("连接失败,执行重连");connect(bootstrap, IP, port);}});}
      
      1. 以上代码就实现了重连机制 , 但是在通常情况下连接失败不会立即重连 , 而是通过一个指数退避的方式 , 比如 每隔1秒、2秒、4秒、8秒 , 以2的次幂来实现建立连接 , 然后到达一定次数之后就放弃重连

          connect(bootstrap , "127.0.0.1" , 8000 , 5);public static void connect(Bootstrap bootstrap, String IP, int port ,int maxRetry , int... retryIndex) {// 建立连接bootstrap.connect(IP, port).addListener(future -> {// 由于闭包特性  不能修改外部的变量 所有需要在闭包内定义一个相同的变量  拷贝外部变量的值int[] finalRetryIndex ;if (future.isSuccess()) {System.out.println("连接成功");} else if(maxRetry == 0){System.out.println("到达重试最大次数,放弃重连");}else {// 初始化  重试计数if(retryIndex.length == 0) {finalRetryIndex = new int[] {0};}else {finalRetryIndex = retryIndex;}//计算时间间隔int delay = 1 << finalRetryIndex[0];// 执行重试System.out.println(new Date()+"连接失败,剩余重连次数:"+maxRetry+","+delay+"秒后执行第"+(finalRetryIndex[0]+1)+"次重连...");bootstrap.config().group().schedule(()->{connect(bootstrap, IP, port , maxRetry-1 , finalRetryIndex[0]+1);}, delay, TimeUnit.SECONDS);}});}执行结果:Thu Dec 27 11:04:19 CST 2018连接失败,剩余重连次数:5,1秒后执行第1次重连...Thu Dec 27 11:04:21 CST 2018连接失败,剩余重连次数:4,2秒后执行第2次重连...Thu Dec 27 11:04:24 CST 2018连接失败,剩余重连次数:3,4秒后执行第3次重连...Thu Dec 27 11:04:29 CST 2018连接失败,剩余重连次数:2,8秒后执行第4次重连...Thu Dec 27 11:04:38 CST 2018连接失败,剩余重连次数:1,16秒后执行第5次重连...到达重试最大次数,放弃重连
        
        1. 从上面的代码中我们可以看到 , 通过判断是否连接成功以及剩余重试次数 , 分别执行不同的逻辑

          1. 如果连接成功则打印连接成功的消息
          2. 如果连接失败 , 但是重试次数已经用完则放弃连接
          3. 如果连接失败 , 但是连接没有用完则计算下一次重试时间间隔 , 然后定时重连
        2. 从上面代码中我们可以看到 , 定时任务是调用bootstrap.config().group().schedule() , 其中bootStrap.config()这个方法返回的是BootStrapConfig , 他是对BootStrap 参数配置的抽象 , 然后ootstrap.config().group() 返回的就是我们一开始设置的线程模型workerGroup , 最后调用schedule() 方法就可以实现定时任务逻辑了。
  3. 客户端启动其他方法

    1. attr(): attr()方法可以给客户端channel也就是NioSocketChannel绑定自定义属性 , 然后我们通过channel.attr()取出属性。 说白了就是给NioSocketChannel维护一个Map 而已

       //设置属性bootstrap.attr(AttributeKey.newInstance("clientName"), "NettyClient");//业务逻辑bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {// 取出属性Attribute<Object> attr = ch.attr(AttributeKey.valueOf("clientName"));System.out.println("客户端名称:"+attr.get());}});
      
    2. option(): option()可以给连接设置一些TCP底层的相关属性 : (ChannelOption相关参数详解在 上一节《服务端启动流程》中有连接地址)

       // 设置TCP 相关的属性// 设置连接超时时间bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);// 开启TCP 心跳机制bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
      
  4. 总结:

    1. 在本节中我们学习了Netty客户端启动的流程 , 一句话来说就是: 创建一个引导类 , 然后给他指定线程 , IO模型 , 指定业务逻辑 ,连接特定的IP:port 客户端就启动起来了
    2. 然后我们学习到 connect()方法时异步的 , 我们可以通过异步回调机制来实现指数退避重连机制。
    3. 最后我们讨论了Netty客户端启动的额外参数 , 只要包括给客户端Channel 绑定自定义属性 , 设置TCP底层参数。
  5. 疑问:

    1. 客户端Channel设置的attr是否会被服务端接收到,并且以此进行必要的参数传递?

      1. 答: 客户端Channel 会被服务端接收到。

Netty实战 IM即时通讯系统(五)客户端启动流程相关推荐

  1. Netty实战 IM即时通讯系统(十二)构建客户端与服务端pipeline

    Netty实战 IM即时通讯系统(十二)构建客户端与服务端pipeline 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向 ...

  2. Netty实战 IM即时通讯系统(十)实现客户端和服务端收发消息

    Netty实战 IM即时通讯系统(十)实现客户端和服务端收发消息 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向通信 数据 ...

  3. Netty实战 IM即时通讯系统(九)实现客户端登录

    ## Netty实战 IM即时通讯系统(九)实现客户端登录 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向通信 数据传输载 ...

  4. Netty实战 IM即时通讯系统(八)服务端和客户端通信协议编解码

    Netty实战 IM即时通讯系统(八)服务端和客户端通信协议编解码 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向通信 数 ...

  5. Netty实战 IM即时通讯系统(六)实战: 客户端和服务端双向通信

    ## Netty实战 IM即时通讯系统(六)实战: 客户端和服务端双向通信 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 实战: 客户端和服务端双向通信 数据传输载 ...

  6. Netty实战 IM即时通讯系统(十一)pipeline与channelHandler

    Netty实战 IM即时通讯系统(十一)pipeline与channelHandler 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端 ...

  7. Netty实战 IM即时通讯系统(七)数据传输载体ByteBuf介绍

    ## Netty实战 IM即时通讯系统(七)数据传输载体ByteBuf介绍 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向 ...

  8. Netty实战 IM即时通讯系统(四)服务端启动流程

    ## Netty实战 IM即时通讯系统(四)服务端启动流程 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 实战: 客户端和服务端双向通信 数据传输载体ByteBuf ...

  9. Netty实战 IM即时通讯系统(三)Netty环境配置

    ## Netty实战 IM即时通讯系统(三)Netty环境配置 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 实战: 客户端和服务端双向通信 数据传输载体ByteB ...

最新文章

  1. matplotlib cmap
  2. 高斯旋转热源与双椭球热源_电力分公司:多措并举保证供暖质量效益双提升
  3. 如何创建和维护你自己的man手册
  4. 第一集 企业IT体系结构
  5. mysql导入本地sql脚本的两种方式
  6. h3c s7506e 配置手册_H3C交换机s5500Web登录配置
  7. primefaces_PrimeFaces扩展中的全新JSF组件
  8. 串口UART串行总线协议
  9. SinGAN: Learning a Generative Model from a Single Natural Image
  10. ajax 文件上传,ajax
  11. JAVA“类”数组的创建与调用
  12. data标签怎么爬虫_scrapy爬虫笔记(1):scrapy基本使用
  13. fp算法例题_机器学习-FPGROWTH算法.pptx
  14. Devcpp使用技巧
  15. Scala中的集合排序
  16. 解决电脑不能进入BIOS页面
  17. 英文电影经典台词整理(原创)
  18. html载入3d模型,webGL3D模型的加载与使用
  19. Java窗体图书管理系统Java图书借阅管理系统(图书借阅系统)
  20. 【SpringBoot】人工更新SpringBoot项目,Jar包太大问题解决,SpringBoot瘦包

热门文章

  1. [na]tcpdump参数应用参考
  2. PHP学习:文件操作
  3. 每日程序C语言6-判断某范围之间的素数
  4. 判断是否是数组的方法
  5. Java黑皮书课后题第1章:1.7(求π的近似值)编写程序,显示4*(1-1/3+1/5-1/7+1/9-1/11【+1/13】)
  6. java bufferedinputstream 编码_java中关于编码的问题(字符转换流及字符缓冲流 )
  7. getchar、scanf以及缓冲区的概念
  8. PHP 使用程序进行数据库字典文件生成 导出数据库字典
  9. 年报统计系统—基本信息模块的目标文档
  10. 如何把微信文章中的语音/音乐下载下来