Netty实战 IM即时通讯系统(五)客户端启动流程
##
Netty實(shí)戰(zhàn) IM即時(shí)通訊系統(tǒng)(五)客戶端啟動(dòng)流程零、 目錄
- Netty 簡介
- Netty 環(huán)境配置
- 服務(wù)端啟動(dòng)流程
- 實(shí)戰(zhàn): 客戶端和服務(wù)端雙向通信
- 數(shù)據(jù)傳輸載體ByteBuf介紹
- 客戶端與服務(wù)端通信協(xié)議編解碼
- 實(shí)現(xiàn)客戶端登錄
- 實(shí)現(xiàn)客戶端與服務(wù)端收發(fā)消息
- pipeline與channelHandler
- 構(gòu)建客戶端與服務(wù)端pipeline
- 拆包粘包理論與解決方案
- channelHandler的生命周期
- 使用channelHandler的熱插拔實(shí)現(xiàn)客戶端身份校驗(yàn)
- 客戶端互聊原理與實(shí)現(xiàn)
- 群聊的發(fā)起與通知
- 群聊的成員管理(加入與退出,獲取成員列表)
- 群聊消息的收發(fā)及Netty性能優(yōu)化
- 心跳與空閑檢測
- 總結(jié)
- 擴(kuò)展
五、 客戶端啟動(dòng)流程
客戶端啟動(dòng)demo
/*** 客戶端啟動(dòng)流程* */public class Test_05_客戶端啟動(dòng)流程 {public static void main(String[] args) {NioEventLoopGroup workerGroup = new NioEventLoopGroup();Bootstrap bootstrap = new Bootstrap();bootstrap// 指定線程模型.group(workerGroup)// 指定IO 模型.channel(NioSocketChannel.class)// 指定業(yè)務(wù)處理邏輯.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("連接失敗");}});}}失敗重連
在網(wǎng)絡(luò)差的情況下 , 客戶端第一次連接可能會(huì)失敗 , 這個(gè)時(shí)候我們可能會(huì)嘗試重新連接 , 重新連接的邏輯寫在連接失敗的邏輯塊里
// 建立連接bootstrap.connect("127.0.0.1" , 8000).addListener(future ->{if(future.isSuccess()) {System.out.println("連接成功");}else {System.out.println("連接失敗");//TODO: 重新連接邏輯}});重新連接時(shí)依然是調(diào)用相同的邏輯 , 所以我們把連接的代碼抽取出來, 實(shí)現(xiàn)代碼復(fù)用 , 在連接失敗的情況下使用遞歸的方法 實(shí)現(xiàn)重連
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("連接失敗,執(zhí)行重連");connect(bootstrap, IP, port);}});}以上代碼就實(shí)現(xiàn)了重連機(jī)制 , 但是在通常情況下連接失敗不會(huì)立即重連 , 而是通過一個(gè)指數(shù)退避的方式 , 比如 每隔1秒、2秒、4秒、8秒 , 以2的次冪來實(shí)現(xiàn)建立連接 , 然后到達(dá)一定次數(shù)之后就放棄重連
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 -> {// 由于閉包特性 不能修改外部的變量 所有需要在閉包內(nèi)定義一個(gè)相同的變量 拷貝外部變量的值int[] finalRetryIndex ;if (future.isSuccess()) {System.out.println("連接成功");} else if(maxRetry == 0){System.out.println("到達(dá)重試最大次數(shù),放棄重連");}else {// 初始化 重試計(jì)數(shù)if(retryIndex.length == 0) {finalRetryIndex = new int[] {0};}else {finalRetryIndex = retryIndex;}//計(jì)算時(shí)間間隔int delay = 1 << finalRetryIndex[0];// 執(zhí)行重試System.out.println(new Date()+"連接失敗,剩余重連次數(shù):"+maxRetry+","+delay+"秒后執(zhí)行第"+(finalRetryIndex[0]+1)+"次重連...");bootstrap.config().group().schedule(()->{connect(bootstrap, IP, port , maxRetry-1 , finalRetryIndex[0]+1);}, delay, TimeUnit.SECONDS);}});}執(zhí)行結(jié)果:Thu Dec 27 11:04:19 CST 2018連接失敗,剩余重連次數(shù):5,1秒后執(zhí)行第1次重連...Thu Dec 27 11:04:21 CST 2018連接失敗,剩余重連次數(shù):4,2秒后執(zhí)行第2次重連...Thu Dec 27 11:04:24 CST 2018連接失敗,剩余重連次數(shù):3,4秒后執(zhí)行第3次重連...Thu Dec 27 11:04:29 CST 2018連接失敗,剩余重連次數(shù):2,8秒后執(zhí)行第4次重連...Thu Dec 27 11:04:38 CST 2018連接失敗,剩余重連次數(shù):1,16秒后執(zhí)行第5次重連...到達(dá)重試最大次數(shù),放棄重連客戶端啟動(dòng)其他方法
attr(): attr()方法可以給客戶端channel也就是NioSocketChannel綁定自定義屬性 , 然后我們通過channel.attr()取出屬性。 說白了就是給NioSocketChannel維護(hù)一個(gè)Map 而已
//設(shè)置屬性bootstrap.attr(AttributeKey.newInstance("clientName"), "NettyClient");//業(yè)務(wù)邏輯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());}});option(): option()可以給連接設(shè)置一些TCP底層的相關(guān)屬性 : (ChannelOption相關(guān)參數(shù)詳解在 上一節(jié)《服務(wù)端啟動(dòng)流程》中有連接地址)
// 設(shè)置TCP 相關(guān)的屬性// 設(shè)置連接超時(shí)時(shí)間bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);// 開啟TCP 心跳機(jī)制bootstrap.option(ChannelOption.SO_KEEPALIVE, true);總結(jié):
疑問:
總結(jié)
以上是生活随笔為你收集整理的Netty实战 IM即时通讯系统(五)客户端启动流程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Netty实战 IM即时通讯系统(四)服
- 下一篇: Netty实战 IM即时通讯系统(六)实