最近在学习netty,做一个netty的小demo吧
PS(本片博客参考了白贺翔老师的netty视频教程)
pom文件
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
Client客户端 HeatBeatClient.java
package com.function.netty.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class HeatBeatClient {
private static Channel channel;
private static EventLoopGroup group;
public static void main(String[] args) {
initclient();
}
public static void initclient(){
group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline()
.addLast(new ObjectEncoder())
.addLast(new ObjectDecoder(ClassResolvers.weakCachingResolver(null)))
.addLast(new HeartBeatClientHandler());
}
});
try {
channel = b.connect("127.0.0.1",6789).sync().channel();
channel.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
}
}
Server端 HeartBeatServer.java
package com.function.netty.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class HeartBeatServer {
public static void main(String[] args) {
EventLoopGroup pGroup = new NioEventLoopGroup();
EventLoopGroup cGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(pGroup,cGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline()
.addLast(new ObjectEncoder())
.addLast(new ObjectDecoder(ClassResolvers.weakCachingResolver(null)))
.addLast(new HeatBeatServerHandler());
}
});
try {
Channel channel = b.bind("127.0.0.1",6789).sync().channel();
channel.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
pGroup.shutdownGracefully();
cGroup.shutdownGracefully();
}
}
测试功能时启动这两个main函数即可。但是还需要server和client两个handler
client端处理逻辑 HeartBeatClientHandler.java
package com.function.netty.client;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class HeartBeatClientHandler extends ChannelHandlerAdapter{
private ScheduledExecutorService sch = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> future;
private String keyWord = "KEY_SUCCESS";
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String message = (String) msg;
if(message.equals(keyWord)) {
this.future = this.sch.scheduleWithFixedDelay(new ScheduledExecutorThread(ctx), 2, 2, TimeUnit.SECONDS);
}else{
System.out.println(message);
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("正在连接"+ctx.channel().remoteAddress());
ctx.writeAndFlush(keyWord);
}
/**
* @Description: 当Netty由于IO错误或者处理器在处理事件时抛出异常时调用
* @Date: 2018/12/18 15:21
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
private class ScheduledExecutorThread implements Runnable{
private final ChannelHandlerContext ctx;
ScheduledExecutorThread(final ChannelHandlerContext ctx){
this.ctx = ctx;
}
@Override
public void run() {
ctx.writeAndFlush("客户端普通消息");
}
}
}
server端处理逻辑HeatBeatServerHandler.java
package com.function.netty.server;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public class HeatBeatServerHandler extends ChannelHandlerAdapter{
private String keyword = "KEY_SUCCESS";
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String message = (String) msg;
if(message.equals(keyword)){
System.out.println(message);
ctx.writeAndFlush(keyword);
}else{
System.out.println(message);
ctx.writeAndFlush("服务端普通消息");
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("建立连接的客户端地址是"+ctx.channel().remoteAddress());
}
}
至此代码已全部粘贴,具体流程是这样的:
1、先启动server端,再启动client端。
2、启动client之后连两端建立连接,触发了HeartBeatClientHandler中的channelActive方法,然后发送key到服务端,服务端接收信息方法中会判断是否为key,是就返回客户端key,否就返回普通字符串。
3、客户端的channelRead方法接收到了key,开启线程池,
this.future = this.sch.scheduleWithFixedDelay(new ScheduledExecutorThread(ctx), 2, 2, TimeUnit.SECONDS);
两秒钟之后每两秒执行一次。
我们看一下scheduleWithFixedDelay()这个方法,第一个参数就是Runnable
定义了一个内部类 ScheduledExecutorThread 实现Runnable接口,重写run方法,利用传入的ChannelHandlerContext 去往服务端写一句话ctx.writeAndFlush("客户端普通消息")。
4、服务端channelRead方法接收到信息,并不是key就直接输出到控制台并且再写回客户端,客户端这时接收到数据判断不是key输出到控制台就不处理了,因为有线程已经在跑了。
5、看起来很绕,其实很简单的处理,接下来看控制台。
server端:
客户端: