基于Netty5.0案例八服务端心跳包

前言介绍:
本案例主要介绍服务端心跳包使用
本案例心跳包主要用于服务端在读、写、读写超时内做出的相应处理。
代码拿到手后可以最好测试下,事必躬亲,无论案例如何明白也得自己测试。

环境需求:【一下内容下文提供下载】
1、Java
1.1、jdk1.7
1.2、Eclipse
2、netty-all-5.0.0.Alpha1.jar

代码部分:

ChildChannelHandler.java

import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;

public class ChildChannelHandler extends ChannelInitializer{

@Override
protected void initChannel(SocketChannel e) throws Exception {

System.out.println("报告");
System.out.println("信息:有一客户端链接到本服务端");
System.out.println("IP:" + e.localAddress().getHostName());
System.out.println("Port:" + e.localAddress().getPort());
System.out.println("报告完毕");

/**
* 心跳包
* 1、readerIdleTimeSeconds 读超时时间
* 2、writerIdleTimeSeconds 写超时时间
* 3、allIdleTimeSeconds 读写超时时间
* 4、TimeUnit.SECONDS 秒[默认为秒,可以指定]
*/
e.pipeline().addLast(new IdleStateHandler(2, 2, 2));
// 基于换行符号解码器
e.pipeline().addLast(new LineBasedFrameDecoder(1024));
// 解码转String
e.pipeline().addLast(new StringDecoder(Charset.forName("GBK")));
// 编码器 String
e.pipeline().addLast(new StringEncoder(Charset.forName("GBK")));
// 处理心跳 【放在编码解码的下面,因为这个是通道有处理顺序】
e.pipeline().addLast(new MyIdleHandler());
// 在管道中添加我们自己的接收数据实现方法
e.pipeline().addLast(new MyServerHanlder());

}

}

MyIdleHandler.java

import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

public class MyIdleHandler extends ChannelHandlerAdapter {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent e = (IdleStateEvent) evt;

if (e.state() == IdleState.READER_IDLE) {
System.out.println("--- Reader Idle ---");

ctx.writeAndFlush("读取等待:客户端你在吗... ...\r\n");

// ctx.close();
} else if (e.state() == IdleState.WRITER_IDLE) {
System.out.println("--- Write Idle ---");

ctx.writeAndFlush("写入等待:客户端你在吗... ...\r\n");
// ctx.close();
} else if (e.state() == IdleState.ALL_IDLE) {
System.out.println("--- All_IDLE ---");

ctx.writeAndFlush("全部时间:客户端你在吗... ...\r\n");

}

}
}
}

MyServerHanlder.java

import java.util.Date;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.bytes.ByteArrayDecoder;

public class MyServerHanlder extends ChannelHandlerAdapter{

/*
* channelAction
*
* channel 通道
* action 活跃的
*
* 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
*
*/
public void channelActive(ChannelHandlerContext ctx) throws Exception {

System.out.println(ctx.channel().localAddress().toString()+" channelActive");

//通知您已经链接上客户端
String str = "您已经开启与服务端链接"+" "+ctx.channel().id()+new Date()+" "+ctx.channel().localAddress();
ctx.writeAndFlush(str);

}

/*
* channelInactive
*
* channel 通道
* Inactive 不活跃的
*
* 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
*
*/
public void channelInactive(ChannelHandlerContext ctx) throws Exception {

System.out.println(ctx.channel().localAddress().toString()+" channelInactive");

}

/*
* channelRead
*
* channel 通道
* Read 读
*
* 简而言之就是从通道中读取数据,也就是服务端接收客户端发来的数据
* 但是这个数据在不进行解码时它是ByteBuf类型的后面例子我们在介绍
*
*/
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {

//注意此处已经不需要手工解码了
System.out.println(ctx.channel().id()+""+new Date()+" "+msg);

//通知您已经链接上客户端[给客户端穿回去的数据加个换行]
String str = "服务端收到:"+ctx.channel().id()+new Date()+" "+msg+"\r\n";

//发送给客户端【可以开启关闭用于测试心跳包】
ctx.writeAndFlush(str);
}

/*
* channelReadComplete
*
* channel 通道
* Read 读取
* Complete 完成
*
* 在通道读取完成后会在这个方法里通知,对应可以做刷新操作
* ctx.flush()
*
*/
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}

/*
* exceptionCaught
*
* exception 异常
* Caught 抓住
*
* 抓住异常,当发生异常的时候,可以做一些相应的处理,比如打印日志、关闭链接
*
*/
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
ctx.close();
System.out.println("异常信息:\r\n"+cause.getMessage());
}
}

NettyServer.java

package com.itstack.netty.idle;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {

public static void main(String[] args) {

try {
System.out.println("服务端开启等待连接... ...");
new NettyServer().bing(7397);
} catch (Exception e) {
e.printStackTrace();
}

}

public void bing(int port) throws Exception{

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();

try {

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workGroup);
b.channel(NioServerSocketChannel.class);
b.option(ChannelOption.SO_BACKLOG, 1024);
b.childHandler(new ChildChannelHandler());

ChannelFuture f = b.bind(port).sync();

f.channel().closeFuture().sync();

} finally {

bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}

}

}


猜你喜欢

转载自blog.csdn.net/hewenya12/article/details/49362937