netty心跳包,只要在netty服务端发送数据设置吗

sponsored links
Netty实现服务端客户端长连接通讯及心跳检测
通过netty实现服务端与客户端的长连接通讯,及心跳检测。
       基本思路:netty服务端通过一个Map保存所有连接上来的客户端SocketChannel,客户端的Id作为Map的key。每次服务器端如果要向某个客户端发送消息,只需根据ClientId取出对应的SocketChannel,往里面写入message即可。心跳检测通过IdleEvent 事件,定时向服务端放送Ping消息,检测SocketChannel是否终断。
        环境JDK1.8 和netty5
        以下是具体的代码实现和介绍:
1公共的Share部分(主要包含消息协议类型的定义)
     设计消息类型:
public enum
PING,ASK,REPLY,LOGIN
Message基类:
//必须实现序列,serialVersionUID 一定要有,否者在netty消息序列化反序列化会有问题,接收不到消息!!!
public abstract class BaseMsg
implements Serializable {
private static final long serialVersionUID = 1L;
private MsgT
//必须唯一,否者会出现channel调用混乱
private String clientId;
//初始化客户端id
public BaseMsg() {
this.clientId = Constants.getClientId();
public String getClientId() {
return clientId;
public void setClientId(String clientId) {
this.clientId = clientId;
public MsgType getType() {
public void setType(MsgType type) {
this.type =
常量设置:
public class Constants {
private static String clientId;
public static String getClientId() {
return clientId;
public static void setClientId(String clientId) {
Constants.clientId = clientId;
登录类型消息:
public class LoginMsg extends BaseMsg {
private String userN
public LoginMsg() {
setType(MsgType.LOGIN);
public String getUserName() {
return userN
public void setUserName(String userName) {
this.userName = userN
public String getPassword() {
public void setPassword(String password) {
this.password =
心跳检测Ping类型消息:
public class PingMsg extends BaseMsg {
public PingMsg() {
setType(MsgType.PING);
请求类型消息:
public class AskMsg extends BaseMsg {
public AskMsg() {
setType(MsgType.ASK);
private AskP
public AskParams getParams() {
public void setParams(AskParams params) {
this.params =
//请求类型参数
//必须实现序列化接口
public class AskParams implements Serializable {
private static final long serialVersionUID = 1L;
public String getAuth() {
public void setAuth(String auth) {
this.auth =
响应类型消息:
public class ReplyMsg extends BaseMsg {
public ReplyMsg() {
setType(MsgType.REPLY);
private ReplyB
public ReplyBody getBody() {
public void setBody(ReplyBody body) {
this.body =
//相应类型body对像
public class ReplyBody implements Serializable {
private static final long serialVersionUID = 1L;
public class ReplyClientBody extends ReplyBody {
private String clientI
public ReplyClientBody(String clientInfo) {
this.clientInfo = clientI
public String getClientInfo() {
return clientI
public void setClientInfo(String clientInfo) {
this.clientInfo = clientI
public class ReplyServerBody extends ReplyBody {
private String serverI
public ReplyServerBody(String serverInfo) {
this.serverInfo = serverI
public String getServerInfo() {
return serverI
public void setServerInfo(String serverInfo) {
this.serverInfo = serverI
2 Server端:主要包含对SocketChannel引用的Map,ChannelHandler的实现和Bootstrap.
public class NettyChannelMap {
private static Map&String,SocketChannel& map=new ConcurrentHashMap&String, SocketChannel&();
public static void add(String clientId,SocketChannel socketChannel){
map.put(clientId,socketChannel);
public static Channel get(String clientId){
return map.get(clientId);
public static void remove(SocketChannel socketChannel){
for (Map.Entry entry:map.entrySet()){
if (entry.getValue()==socketChannel){
map.remove(entry.getKey());
public class NettyServerHandler extends SimpleChannelInboundHandler&BaseMsg& {
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//channel失效,从Map中移除
NettyChannelMap.remove((SocketChannel)ctx.channel());
protected void messageReceived(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception {
if(MsgType.LOGIN.equals(baseMsg.getType())){
LoginMsg loginMsg=(LoginMsg)baseM
if(&robin&.equals(loginMsg.getUserName())&&&yao&.equals(loginMsg.getPassword())){
//登录成功,把channel存到服务端的map中
NettyChannelMap.add(loginMsg.getClientId(),(SocketChannel)channelHandlerContext.channel());
System.out.println(&client&+loginMsg.getClientId()+& 登录成功&);
if(NettyChannelMap.get(baseMsg.getClientId())==null){
//说明未登录,或者连接断了,服务器向客户端发起登录请求,让客户端重新登录
LoginMsg loginMsg=new LoginMsg();
channelHandlerContext.channel().writeAndFlush(loginMsg);
switch (baseMsg.getType()){
case PING:{
PingMsg pingMsg=(PingMsg)baseM
PingMsg replyPing=new PingMsg();
NettyChannelMap.get(pingMsg.getClientId()).writeAndFlush(replyPing);
case ASK:{
//收到客户端的请求
AskMsg askMsg=(AskMsg)baseM
if(&authToken&.equals(askMsg.getParams().getAuth())){
ReplyServerBody replyBody=new ReplyServerBody(&server info $$$$ !!!&);
ReplyMsg replyMsg=new ReplyMsg();
replyMsg.setBody(replyBody);
NettyChannelMap.get(askMsg.getClientId()).writeAndFlush(replyMsg);
case REPLY:{
//收到客户端
ReplyMsg replyMsg=(ReplyMsg)baseM
ReplyClientBody clientBody=(ReplyClientBody)replyMsg.getBody();
System.out.println(&receive client msg: &+clientBody.getClientInfo());
default:break;
ReferenceCountUtil.release(baseMsg);
ServerBootstrap:
public class NettyServerBootstrap {
private int
private SocketChannel socketC
public NettyServerBootstrap(int port) throws InterruptedException {
this.port =
private void bind() throws InterruptedException {
EventLoopGroup boss=new NioEventLoopGroup();
EventLoopGroup worker=new NioEventLoopGroup();
ServerBootstrap bootstrap=new ServerBootstrap();
bootstrap.group(boss,worker);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.option(ChannelOption.SO_BACKLOG, 128);
//通过NoDelay禁用Nagle,使消息立即发出去,不用等待到一定的数据量才发出去
bootstrap.option(ChannelOption.TCP_NODELAY, true);
//保持长连接状态
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
bootstrap.childHandler(new ChannelInitializer&SocketChannel&() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline p = socketChannel.pipeline();
p.addLast(new ObjectEncoder());
p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
p.addLast(new NettyServerHandler());
ChannelFuture f= bootstrap.bind(port).sync();
if(f.isSuccess()){
System.out.println(&server start&);
public static void main(String []args) throws InterruptedException {
NettyServerBootstrap bootstrap=new NettyServerBootstrap(9);
while (true){
SocketChannel channel=(SocketChannel)NettyChannelMap.get(&001&);
if(channel!=null){
AskMsg askMsg=new AskMsg();
channel.writeAndFlush(askMsg);
TimeUnit.SECONDS.sleep(5);
3 Client端:包含发起登录,发送心跳,及对应消息处理
public class NettyClientHandler extends SimpleChannelInboundHandler&BaseMsg& {
//利用写空闲发送心跳检测消息
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent e = (IdleStateEvent)
switch (e.state()) {
case WRITER_IDLE:
PingMsg pingMsg=new PingMsg();
ctx.writeAndFlush(pingMsg);
System.out.println(&send ping to server-&);
protected void messageReceived(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception {
MsgType msgType=baseMsg.getType();
switch (msgType){
case LOGIN:{
//向服务器发起登录
LoginMsg loginMsg=new LoginMsg();
loginMsg.setPassword(&yao&);
loginMsg.setUserName(&robin&);
channelHandlerContext.writeAndFlush(loginMsg);
case PING:{
System.out.println(&receive ping from server-&);
case ASK:{
ReplyClientBody replyClientBody=new ReplyClientBody(&client info **** !!!&);
ReplyMsg replyMsg=new ReplyMsg();
replyMsg.setBody(replyClientBody);
channelHandlerContext.writeAndFlush(replyMsg);
case REPLY:{
ReplyMsg replyMsg=(ReplyMsg)baseM
ReplyServerBody replyServerBody=(ReplyServerBody)replyMsg.getBody();
System.out.println(&receive client msg: &+replyServerBody.getServerInfo());
default:break;
ReferenceCountUtil.release(msgType);
public class NettyClientBootstrap {
private int
private SocketChannel socketC
private static final EventExecutorGroup group = new DefaultEventExecutorGroup(20);
public NettyClientBootstrap(int port, String host) throws InterruptedException {
this.port =
this.host =
private void start() throws InterruptedException {
EventLoopGroup eventLoopGroup=new NioEventLoopGroup();
Bootstrap bootstrap=new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE,true);
bootstrap.group(eventLoopGroup);
bootstrap.remoteAddress(host,port);
bootstrap.handler(new ChannelInitializer&SocketChannel&() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new IdleStateHandler(20,10,0));
socketChannel.pipeline().addLast(new ObjectEncoder());
socketChannel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
socketChannel.pipeline().addLast(new NettyClientHandler());
ChannelFuture future =bootstrap.connect(host,port).sync();
if (future.isSuccess()) {
socketChannel = (SocketChannel)future.channel();
System.out.println(&connect server
public static void main(String[]args) throws InterruptedException {
Constants.setClientId(&001&);
NettyClientBootstrap bootstrap=new NettyClientBootstrap(9,&localhost&);
LoginMsg loginMsg=new LoginMsg();
loginMsg.setPassword(&yao&);
loginMsg.setUserName(&robin&);
bootstrap.socketChannel.writeAndFlush(loginMsg);
while (true){
TimeUnit.SECONDS.sleep(3);
AskMsg askMsg=new AskMsg();
AskParams askParams=new AskParams();
askParams.setAuth(&authToken&);
askMsg.setParams(askParams);
bootstrap.socketChannel.writeAndFlush(askMsg);
具体的例子和相应pom.xml 见
需求: 向lcbserver发长连接 原始方法: java public SampleResult runTest(JavaSamplerContext arg0) { SampleResult results = new SampleResult(); int i = 0; Long totaltime = try { results.setS ...
原文地址:http://www.vckbase.com/index.php/wv/1561文章概要:源码使用了高级的完成端口(IOCP)技术,该技术可以有效地服务于多客户端.本文提出了一些IOCP编程中出现的实际问题的解决方法,并提供了一个简单的echo版本的可以传输文件的客户端/服务器程序. 源码使用了高级的完成端口(IOCP)技术,该技术可以有效地服务于 ...
一个简单的完成端口(服务端/客户端)类作者:spinoza翻译:麦子芽儿, POWERCPP(后面部分内容) 下载源代码 原文网址:http://www.codeproject.com/KB/IP/iocp_server_client.aspx 源码使用了高级的完成端口(IOCP)技术,该技术可以有效地服务于多客户端.本文提出了一些IOCP编程中出现的实际问 ...
http://blog.csdn.net/zhangzeyuaaa/article/details/
目录(?)[-] 无线移动网络的特点 android系统的推送和IOS的推送有什么区别 推送的实现方式
互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接( ...
阅读60 评论0
互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了,所以才会出现像MQTT这种轻量级低消耗的协议来维护长连接,那么要如何维护长连接呢?
在写之前,我们首先了解一 ...netty 服务端怎么监测链接_百度知道
netty 服务端怎么监测链接
我有更好的答案
首先要有心跳包检测的类 设定多少时间没有在通道里面读取到信息则判定为断线,把通道清除掉。使用Netty实现心跳检测:新建Java工程,并导入netty使用的jar包,最好将源码包也放在本工程下,便于了解netty的源码实现。可以从netty自带的example中复制一个例子过来,在此基础上进行修改。在此基础上对代码进行改造。打开EchoServer.java,添加空闲检测类。编写心跳检测处理类。并将此类添加到pinpline的handler里面。改造完了服务端,需要对客户端内容改造一下。启动客户端后,先发一个“hello”消息,然后等候服务端心跳信息“ping”,收到心跳后,回复心跳响应“ok”。心跳消息可以根据需要进行定义。修改的类为EchoClientHandler。为方便查看可以将netty的日志打开。即:将此句p.addLast(new LoggingHandler(LogLevel.INFO));前面的注释去掉,执行测试一下。查看服务端,可以看到心跳包和心跳响应。将客户端回复心跳的内容删除,再执行查看结果。此时可以看到服务端在30秒内没有收到心跳,认为客户端连接出现问题,将此连接关闭。
采纳率:86%
来自团队:
首先要有心跳包检测的类 设定多少时间没有在通道里面读取到信息则判定为断线,把通道清除掉。
炮兵和步兵(
第七回 袁绍磐河战公孙 孙坚跨江击刘表第八回 王司徒巧使连环计 董太师大闹凤仪亭
2条折叠回答
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。3191人阅读
基于netty的心跳检测,有需要的朋友可以参考下。
这两天由于要给android系统的设备写一个心跳功能,所以在这里写一个基于netty的心跳检测功能。
实现的功能:
1.客户端网络空闲5秒没有进行写操作是,进行发送一次ping心跳给服务端;
2.客户端如果在下一个发送ping心跳周期来临时,还没有收到服务端pong的心跳应答,则失败心跳计数器加1;
3.每当客户端收到服务端的pong心跳应答后,失败心跳计数器清零;
4.如果连续超过3次没有收到服务端的心跳回复,则断开当前连接,在5秒后进行重连操作,直到重连成功,否则每隔5秒又会进行重连;
5.服务端网络空闲状态到达6秒后,服务端心跳失败计数器加1;
6.只要收到客户端的ping消息,服务端心跳失败计数器清零;
7.服务端连续3次没有收到客户端的ping消息后,将关闭链路,释放资源,等待客户端重连;
服务端代码:
package com.kg.netty.
import io.netty.bootstrap.ServerB
import io.netty.channel.ChannelF
import io.netty.channel.ChannelHandlerC
import io.netty.channel.ChannelI
import io.netty.channel.ChannelP
import io.netty.channel.EventLoopG
import io.netty.channel.SimpleChannelInboundH
import io.netty.channel.nio.NioEventLoopG
import io.netty.channel.socket.SocketC
import io.netty.channel.socket.nio.NioServerSocketC
import io.netty.handler.codec.serialization.ClassR
import io.netty.handler.codec.serialization.ObjectD
import io.netty.handler.codec.serialization.ObjectE
import io.netty.handler.timeout.IdleS
import io.netty.handler.timeout.IdleStateE
import io.netty.handler.timeout.IdleStateH
import java.util.concurrent.TimeU
import com.kg.netty.msg.KeepAliveM
import com.kg.utils.C
import com.kg.utils.U
public class KeepAliveServer {
public KeepAliveServer(int port) {
this.port =
// 设置6秒检测chanel是否接受过心跳数据
private static final int READ_WAIT_SECONDS = 6;
// 定义客户端没有收到服务端的pong消息的最大次数
private static final int MAX_UN_REC_PING_TIMES = 3;
public void startServer() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
b = new ServerBootstrap();
b.group(bossGroup, workerGroup);
b.channel(NioServerSocketChannel.class);
b.childHandler(new KeepAliveServerInitializer());
// 服务器绑定端口监听
f = b.bind(port).sync();
// 监听服务器关闭监听,此方法会阻塞
f.channel().closeFuture().sync();
// 可以简写为
/* b.bind(portNumber).sync().channel().closeFuture().sync(); */
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
* 消息处理器
* @author cullen edward
private class KeepAliveServerInitializer extends ChannelInitializer&SocketChannel& {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
* 使用ObjectDecoder和ObjectEncoder
* 因为双向都有写数据和读数据,所以这里需要两个都设置
* 如果只读,那么只需要ObjectDecoder即可
pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
pipeline.addLast("encoder", new ObjectEncoder());
* 这里只监听读操作
* 可以根据需求,监听写操作和总得操作
pipeline.addLast("pong", new IdleStateHandler(READ_WAIT_SECONDS, 0, 0,TimeUnit.SECONDS));
pipeline.addLast("handler", new Heartbeat());
private class Heartbeat extends SimpleChannelInboundHandler&KeepAliveMessage& {
// 失败计数器:未收到client端发送的ping请求
private int unRecPingTimes = 0 ;
// 每个chanel对应一个线程,此处用来存储对应于每个线程的一些基础数据,此处不一定要为KeepAliveMessage对象
ThreadLocal&KeepAliveMessage& localMsgInfo = new ThreadLocal&KeepAliveMessage&();
protected void channelRead0(ChannelHandlerContext ctx, KeepAliveMessage msg) throws Exception {
System.out.println(ctx.channel().remoteAddress() + " Say : sn=" + msg.getSn()+",reqcode="+msg.getReqCode());
// 收到ping消息后,回复
if(Utils.notEmpty(msg.getSn())&&msg.getReqCode()==1){
msg.setReqCode(Constants.RET_CODE);
ctx.channel().writeAndFlush(msg);
// 失败计数器清零
unRecPingTimes = 0;
if(localMsgInfo.get()==null){
KeepAliveMessage localMsg = new KeepAliveMessage();
localMsg.setSn(msg.getSn());
localMsgInfo.set(localMsg);
* 这里可以将设备号放入一个集合中进行统一管理
ctx.channel().close();
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent)
if (event.state() == IdleState.READER_IDLE) {
/*读超时*/
System.out.println("===服务端===(READER_IDLE 读超时)");
// 失败计数器次数大于等于3次的时候,关闭链接,等待client重连
if(unRecPingTimes &= MAX_UN_REC_PING_TIMES){
System.out.println("===服务端===(读超时,关闭chanel)");
// 连续超过N次未收到client的ping消息,那么关闭该通道,等待client重连
ctx.channel().close();
// 失败计数器加1
unRecPingTimes++;
} else if (event.state() == IdleState.WRITER_IDLE) {
/*写超时*/
System.out.println("===服务端===(WRITER_IDLE 写超时)");
} else if (event.state() == IdleState.ALL_IDLE) {
/*总超时*/
System.out.println("===服务端===(ALL_IDLE 总超时)");
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("错误原因:"+cause.getMessage());
if(localMsgInfo.get()!=null){
* 从管理集合中移除设备号等唯一标示,标示设备离线
ctx.channel().close();
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client active ");
super.channelActive(ctx);
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// 关闭,等待重连
ctx.close();
if(localMsgInfo.get()!=null){
* 从管理集合中移除设备号等唯一标示,标示设备离线
System.out.println("===服务端===(客户端失效)");
public void stopServer(){
if(f!=null){
f.channel().close();
* @param args
public static void main(String[] args) {
KeepAliveServer keepAliveServer = new KeepAliveServer(1666);
keepAliveServer.startServer();
客户端代码:
package com.kg.netty.
import io.netty.bootstrap.B
import io.netty.channel.C
import io.netty.channel.ChannelHandlerC
import io.netty.channel.ChannelI
import io.netty.channel.ChannelP
import io.netty.channel.EventLoopG
import io.netty.channel.SimpleChannelInboundH
import io.netty.channel.nio.NioEventLoopG
import io.netty.channel.socket.SocketC
import io.netty.channel.socket.nio.NioSocketC
import io.netty.handler.codec.serialization.ClassR
import io.netty.handler.codec.serialization.ObjectD
import io.netty.handler.codec.serialization.ObjectE
import io.netty.handler.timeout.IdleS
import io.netty.handler.timeout.IdleStateE
import io.netty.handler.timeout.IdleStateH
import java.util.concurrent.E
import java.util.concurrent.ScheduledExecutorS
import java.util.concurrent.TimeU
import com.kg.netty.msg.KeepAliveM
import com.kg.utils.C
public class KeepAliveClient {
private EventLoopG
// 定义客户端没有收到服务端的pong消息的最大次数
private static final int MAX_UN_REC_PONG_TIMES = 3;
// 多长时间未请求后,发送心跳
private static final int WRITE_WAIT_SECONDS = 5;
// 隔N秒后重连
private static final int RE_CONN_WAIT_SECONDS = 5;
// 客户端连续N次没有收到服务端的pong消息
private int unRecPongTimes = 0 ;
private ScheduledExecutorService executorS
// 是否停止
private boolean isStop =
public KeepAliveClient(String host, int port) {
this.host =
this.port =
group = new NioEventLoopGroup();
b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).handler(new HeartbeatInitializer());
public void start() {
connServer();
private void connServer(){
if(executorService!=null){
executorService.shutdown();
executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleWithFixedDelay(new Runnable() {
boolean isConnSucc =
public void run() {
// 重置计数器
unRecPongTimes = 0;
// 连接服务端
if(ch!=null&&ch.isOpen()){
ch.close();
ch = b.connect(host, port).sync().channel();
// 此方法会阻塞
ch.closeFuture().sync();
System.out.println("connect server finish");
} catch (Exception e) {
e.printStackTrace();
isConnSucc =
} finally{
if(isConnSucc){
if(executorService!=null){
executorService.shutdown();
}, RE_CONN_WAIT_SECONDS, RE_CONN_WAIT_SECONDS, TimeUnit.SECONDS);
public class HeartbeatInitializer extends ChannelInitializer&SocketChannel& {
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
pipeline.addLast("encoder", new ObjectEncoder());
pipeline.addLast("ping", new IdleStateHandler(0, WRITE_WAIT_SECONDS, 0,TimeUnit.SECONDS));
// 客户端的逻辑
pipeline.addLast("handler", new ClientHandler());
public class ClientHandler extends SimpleChannelInboundHandler&KeepAliveMessage& {
protected void channelRead0(ChannelHandlerContext ctx, KeepAliveMessage msg)
throws Exception {
System.out.println("Server say : sn=" + msg.getSn()+",reqcode="+msg.getReqCode());
if (Constants.RET_CODE == msg.getReqCode()) {
// 计数器清零
unRecPongTimes = 0;
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client active ");
super.channelActive(ctx);
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client close ");
super.channelInactive(ctx);
if(!isStop){
connServer();
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent)
if (event.state() == IdleState.READER_IDLE) {
/*读超时*/
System.out.println("===服务端===(READER_IDLE 读超时)");
} else if (event.state() == IdleState.WRITER_IDLE) {
/*写超时*/
System.out.println("===服务端===(WRITER_IDLE 写超时)");
if(unRecPongTimes & MAX_UN_REC_PONG_TIMES){
ctx.channel().writeAndFlush(getSrcMsg()) ;
unRecPongTimes++;
ctx.channel().close();
} else if (event.state() == IdleState.ALL_IDLE) {
/*总超时*/
System.out.println("===服务端===(ALL_IDLE 总超时)");
private KeepAliveMessage getSrcMsg(){
KeepAliveMessage keepAliveMessage = new KeepAliveMessage();
keepAliveMessage.setSn("sn_123456abcdfef");
keepAliveMessage.setReqCode(Constants.REQ_CODE);
return keepAliveM
public void stop(){
if(ch!=null&&ch.isOpen()){
ch.close();
if(executorService!=null){
executorService.shutdown();
* @param args
public static void main(String[] args) {
KeepAliveClient keepAliveServer = new KeepAliveClient("127.0.0.1",1666);
keepAliveServer.start();
参考网站:
http://coder.beitown.com/archives/1180
下载工程,请猛戳
http://download.csdn.net/detail/asd2741

我要回帖

更多关于 netty 服务端发送消息 的文章

 

随机推荐