netty心跳过程中 发送消息失败_Netty 4.0 实现心跳检测和断线重连
arg0.pipeline().addLast("ping", new IdleStateHandler(25, 15, 10,TimeUnit.SECONDS));
這個處理器,它的作用就是用來檢測客戶端的讀取超時的,該類的第一個參數是指定讀操作空閑秒數,第二個參數是指定寫操作的空閑秒數,第三個參數是指定讀寫空閑秒數,當有操作操作超出指定空閑秒數時,便會觸發UserEventTriggered事件。所以我們只需要在自己的handler中截獲該事件,然后發起相應的操作即可(比如說發起心跳操作)。以下是我們自定義的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");
// 發送心跳消息
MsgHandleService.getInstance().sendMsgUtil.sendHeartMessage(ctx);
}
}
}
也就是說 服務端在10s內未進行讀寫操作,就會向客戶端發送心跳包,客戶端收到心跳包后立即回復心跳包給服務端,此時服務端就進行了讀操作,也就不會觸發IdleState.READER_IDLE(未讀操作狀態),若客戶端異常掉線了,并不能響應服務端發來的心跳包,在25s后就會觸發IdleState.READER_IDLE(未讀操作狀態),此時服務器就會將通道關閉
客戶端代碼略
二 客戶端實現斷線重連
原理當客戶端連接服務器時
bootstrap.connect(new InetSocketAddress(
serverIP, port));
會返回一個ChannelFuture的對象,我們對這個對象進行監聽
代碼如下:
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,且構造函數變化很大,這里用無參構造。
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 {
// 創建分隔符緩沖對象
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協議的屬性
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, "關閉連接");
}
}
}
監聽到連接服務器失敗時,會在3秒后重新連接(執行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 实现心跳检测和断线重连的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: adc0809引脚图及功能_80C51单
- 下一篇: linux syslog 删除文件_Li