写在文章前:知识来源为《B站》视屏和《netty实战中文版》书籍
Netty基础
- C/S模式、异步
使用idea创建一个简单的异步服务
客户端处理配置类
```
/**
* @Description: 客户端处理配置类
* @Author: Lmy
* @Date: 2020/10/16 4:49 下午
*/
@ChannelHandler.Sharable//表示可以被多个channel安全共享
public class HandlerMonitorClient extends SimpleChannelInboundHandler<ByteBuf> {
/**
* @Date: 2020/10/16 4:52 下午
* @Author: Lmy
* @Description: 消息接收处理
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
System.out.println(byteBuf.toString(CharsetUtil.UTF_8));
}
/**
* @Date: 2020/10/16 4:52 下午
* @Author: Lmy
* @Description: 异常处理
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
/**
* @Date: 2020/10/16 6:44 下午
* @Author: Lmy
* @Description: 通道第一次成功连接的时候触发
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println("通道第一次成功连接的时候触发");
SimpleDateFormat simpleFormatter=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
String format = simpleFormatter.format(new Date());
ctx.writeAndFlush(Unpooled.copiedBuffer(format,CharsetUtil.UTF_8));
}
/**
* @Date: 2020/10/16 6:50 下午
* @Author: Lmy
* @Description: 通道第一次失效的时候调用
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("通道第一次失效的时候调用");
}
}
```
客户端启动类
/**
* @Description: 客户端启动类
* @Author: Lmy
* @Date: 2020/10/16 5:03 下午
*/
public class AppMonitorClient {
private final int port;
private final String host;
public AppMonitorClient(int port, String host) {
this.port = port;
this.host = host;
}
/**
* @Date: 2020/10/16 5:06 下午
* @Author: Lmy
* @Description:
*/
public void run() throws Exception{
EventLoopGroup eventExecutors=new NioEventLoopGroup(); //io线程池
Bootstrap bootstrap=new Bootstrap();//辅助启动类
try {
//配置辅助启动类
bootstrap.group(eventExecutors)//使用的线程
.channel(NioSocketChannel.class)//链接什么类型的通道
.remoteAddress(new InetSocketAddress(host,port)) //绑定地址端口
.handler(new ChannelInitializer<SocketChannel>() {//初始化通道配置
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//pipeline(责任链) 所有的Handler都存在这里
socketChannel.pipeline().addLast(new HandlerMonitorClient());//添加自定义通道
}
});
//链接到远端 等待链接完成
ChannelFuture sync = bootstrap.connect().sync();
//发送消息到服务端 在通道中写数据并且提交
sync.channel().writeAndFlush(Unpooled.copiedBuffer("hello world",CharsetUtil.UTF_8));
//阻塞操作 closeFuture()开启了一个channel监听 通道关闭的时候执行
sync.channel().closeFuture().sync();
} finally {
//资源释放
eventExecutors.shutdownGracefully().sync();
}
}
public static void main(String[] args) {
try {
new AppMonitorClient(8080,"127.0.0.1").run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务器配置类
/**
* @Description: 服务器 io处理类 连接监测
* @Author: Lmy
* @Date: 2020/10/16 5:59 下午
*/
@ChannelHandler.Sharable
public class HandlerMonitorServer extends ChannelInboundHandlerAdapter {
//存储所有的Channel
public static ChannelGroup channelGroup=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* @Date: 2020/10/16 6:06 下午
* @Author: Lmy
* @Description: 处理信息
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in = (ByteBuf) msg;
System.out.println(in.toString(CharsetUtil.UTF_8));//处理接收到的数据
//返回信息给客户端
ctx.writeAndFlush(Unpooled.copiedBuffer("收到信息", CharsetUtil.UTF_8));
}
/**
* @Date: 2020/10/16 6:04 下午
* @Author: Lmy
* @Description: 重写处理异常
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
/**
* @Date: 2020/10/16 6:40 下午
* @Author: Lmy
* @Description: 连接建立后触发 添加到容器
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println("连接建立后触发 添加到容器");
channelGroup.add(channel);
}
/**
* @Date: 2020/10/16 6:43 下午
* @Author: Lmy
* @Description: 连接断开触发 从容器中移除
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println("连接断开触发 从容器中移除");
channelGroup.remove(channel);
}
/**
* @Date: 2020/10/16 6:44 下午
* @Author: Lmy
* @Description: 通道第一次成功连接的时候触发
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println("通道第一次成功连接的时候触发");
SimpleDateFormat simpleFormatter=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
String format = simpleFormatter.format(new Date());
ctx.writeAndFlush(Unpooled.copiedBuffer(format,CharsetUtil.UTF_8));
}
/**
* @Date: 2020/10/16 6:50 下午
* @Author: Lmy
* @Description: 通道第一次失效的时候调用
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("通道第一次失效的时候调用");
}
}
服务器启动类
/**
* @Description: 服务器启动类
* @Author: Lmy
* @Date: 2020/10/16 6:09 下午
*/
public class AppMonitorServer {
private final int port;
public AppMonitorServer(int port) {
this.port = port;
}
/**
* @Date: 2020/10/16 5:06 下午
* @Author: Lmy
* @Description:
*/
public void run() throws Exception {
EventLoopGroup eventExecutors = new NioEventLoopGroup(); //io线程池
ServerBootstrap serverBootstrap = new ServerBootstrap();//辅助启动类
try {
//配置辅助启动类
serverBootstrap.group(eventExecutors)//使用的线程
.channel(NioServerSocketChannel.class)//链接什么类型的通道
.localAddress(new InetSocketAddress(port)) //监听端口
.childHandler(new ChannelInitializer<SocketChannel>() {//初始化通道配置
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//pipeline(责任链) 所有的Handler都存在这里
socketChannel.pipeline().addLast(new HandlerMonitorServer());//添加自定义通道
}
});
//绑定服务器
ChannelFuture sync = serverBootstrap.bind().sync();
//阻塞操作 closeFuture()开启了一个channel监听 当通道关闭的时候执行
sync.channel().closeFuture().sync();
} finally {
//资源释放
eventExecutors.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new AppMonitorServer(8080).run();
}
}
学习小结
- 客户端建立通道并绑定地址与端口
- 服务器绑定端口并监听行为
- 所有操作都是在异步处理