日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

netty心跳过程中 发送消息失败_Netty 4.0 实现心跳检测和断线重连

發(fā)布時間:2024/9/27 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 netty心跳过程中 发送消息失败_Netty 4.0 实现心跳检测和断线重连 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

arg0.pipeline().addLast("ping", new IdleStateHandler(25, 15, 10,TimeUnit.SECONDS));

這個處理器,它的作用就是用來檢測客戶端的讀取超時的,該類的第一個參數(shù)是指定讀操作空閑秒數(shù),第二個參數(shù)是指定寫操作的空閑秒數(shù),第三個參數(shù)是指定讀寫空閑秒數(shù),當有操作操作超出指定空閑秒數(shù)時,便會觸發(fā)UserEventTriggered事件。所以我們只需要在自己的handler中截獲該事件,然后發(fā)起相應的操作即可(比如說發(fā)起心跳操作)。以下是我們自定義的handler中的代碼:

/**

* 一段時間未進行讀寫操作 回調

*/

@Override

public void userEventTriggered(ChannelHandlerContext ctx, Object evt)

throws Exception {

// TODO Auto-generated method stub

super.userEventTriggered(ctx, evt);

if (evt instanceof IdleStateEvent) {

IdleStateEvent event = (IdleStateEvent) evt;

if (event.state().equals(IdleState.READER_IDLE)) {

//未進行讀操作

System.out.println("READER_IDLE");

// 超時關閉channel

ctx.close();

} else if (event.state().equals(IdleState.WRITER_IDLE)) {

} else if (event.state().equals(IdleState.ALL_IDLE)) {

//未進行讀寫

System.out.println("ALL_IDLE");

// 發(fā)送心跳消息

MsgHandleService.getInstance().sendMsgUtil.sendHeartMessage(ctx);

}

}

}

也就是說 服務端在10s內未進行讀寫操作,就會向客戶端發(fā)送心跳包,客戶端收到心跳包后立即回復心跳包給服務端,此時服務端就進行了讀操作,也就不會觸發(fā)IdleState.READER_IDLE(未讀操作狀態(tài)),若客戶端異常掉線了,并不能響應服務端發(fā)來的心跳包,在25s后就會觸發(fā)IdleState.READER_IDLE(未讀操作狀態(tài)),此時服務器就會將通道關閉

客戶端代碼略

二 客戶端實現(xiàn)斷線重連

原理當客戶端連接服務器時

bootstrap.connect(new InetSocketAddress(

serverIP, port));

會返回一個ChannelFuture的對象,我們對這個對象進行監(jiān)聽

代碼如下:

import android.os.Handler;

import android.os.HandlerThread;

import android.os.Message;

import android.util.Log;

import com.ld.qmwj.Config;

import com.ld.qmwj.MyApplication;

import java.net.InetSocketAddress;

import java.nio.charset.Charset;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;

import io.netty.buffer.ByteBuf;

import io.netty.buffer.Unpooled;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelFutureListener;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.ChannelOption;

import io.netty.channel.nio.NioEventLoopGroup;

import io.netty.channel.socket.SocketChannel;

import io.netty.channel.socket.nio.NioSocketChannel;

import io.netty.handler.codec.DelimiterBasedFrameDecoder;

import io.netty.handler.codec.string.StringDecoder;

import io.netty.handler.codec.string.StringEncoder;

/**

* Created by zsg on 2015/11/21.

*/

public class MyClient implements Config {

private static Bootstrap bootstrap;

private static ChannelFutureListener channelFutureListener = null;

public MyClient() {

}

// 初始化客戶端

public static void initClient() {

NioEventLoopGroup group = new NioEventLoopGroup();

// Client服務啟動器 3.x的ClientBootstrap

// 改為Bootstrap,且構造函數(shù)變化很大,這里用無參構造。

bootstrap = new Bootstrap();

// 指定EventLoopGroup

bootstrap.group(group);

// 指定channel類型

bootstrap.channel(NioSocketChannel.class);

// 指定Handler

bootstrap.handler(new ChannelInitializer() {

@Override

protected void initChannel(SocketChannel ch) throws Exception {

// 創(chuàng)建分隔符緩沖對象

ByteBuf delimiter = Unpooled.copiedBuffer("#"

.getBytes());

// 當達到最大長度仍沒找到分隔符 就拋出異常

ch.pipeline().addLast(

new DelimiterBasedFrameDecoder(10000, true, false, delimiter));

// 將消息轉化成字符串對象 下面的到的消息就不用轉化了

//解碼

ch.pipeline().addLast(new StringEncoder(Charset.forName("UTF-8")));

ch.pipeline().addLast(new StringDecoder(Charset.forName("GBK")));

ch.pipeline().addLast(new MyClientHandler());

}

});

//設置TCP協(xié)議的屬性

bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

bootstrap.option(ChannelOption.TCP_NODELAY, true);

bootstrap.option(ChannelOption.SO_TIMEOUT, 5000);

channelFutureListener = new ChannelFutureListener() {

public void operationComplete(ChannelFuture f) throws Exception {

// Log.d(Config.TAG, "isDone:" + f.isDone() + " isSuccess:" + f.isSuccess() +

// " cause" + f.cause() + " isCancelled" + f.isCancelled());

if (f.isSuccess()) {

Log.d(Config.TAG, "重新連接服務器成功");

} else {

Log.d(Config.TAG, "重新連接服務器失敗");

// 3秒后重新連接

f.channel().eventLoop().schedule(new Runnable() {

@Override

public void run() {

doConnect();

}

}, 3, TimeUnit.SECONDS);

}

}

};

}

// 連接到服務端

public static void doConnect() {

Log.d(TAG, "doConnect");

ChannelFuture future = null;

try {

future = bootstrap.connect(new InetSocketAddress(

serverIP, port));

future.addListener(channelFutureListener);

} catch (Exception e) {

e.printStackTrace();

//future.addListener(channelFutureListener);

Log.d(TAG, "關閉連接");

}

}

}

監(jiān)聽到連接服務器失敗時,會在3秒后重新連接(執(zhí)行doConnect方法)

這還不夠,當客戶端掉線時要進行重新連接

在我們自己定義邏輯處理的Handler中

@Override

public void channelInactive(ChannelHandlerContext ctx) throws Exception {

Log.d(Config.TAG, "與服務器斷開連接服務器");

super.channelInactive(ctx);

MsgHandle.getInstance().channel = null;

//重新連接服務器

ctx.channel().eventLoop().schedule(new Runnable() {

@Override

public void run() {

MyClient.doConnect();

}

}, 2, TimeUnit.SECONDS);

ctx.close();

}

3

1

分享到:

2016-02-17 21:42

瀏覽 30989

評論

3 樓

VIP庚

2016-12-23

sdtzyb 寫道

MsgHandle 這個里面寫的是什么為什么需要把??????? MsgHandle.getInstance().channel = null;

弄成空。

能不能把提懂點詳細代碼

channel是客戶端與服務器之間通信的通道,和socket類似,當客戶端與服務器連接成功后,會將chanel保存。這里是客戶端與服務器斷開連接后進行重連,所以要將原先的通道變成空

2 樓

sdtzyb

2016-12-21

MsgHandle 這個里面寫的是什么為什么需要把??????? MsgHandle.getInstance().channel = null;

弄成空。

能不能把提懂點詳細代碼

1 樓

newboy2004

2016-04-21

對netty應用理解的更深入了一點

總結

以上是生活随笔為你收集整理的netty心跳过程中 发送消息失败_Netty 4.0 实现心跳检测和断线重连的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。