我正在参加「掘金·启航计划」
Netty快速入门实例-TCP服务
- 使用IDEA 创建Netty项目
- Netty 服务器在 6668 端口监听,客户端能发送消息给服务器 “hello, 服务器~”
- 服务器可以回复消息给客户端 “hello, 客户端~”
- 目的:对Netty 线程模型 有一个初步认识, 便于理解Netty 模型理论
NettyServer
package com.netty.simple;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @Description: ···
* @author: Freedom
* @QQ: 1556507698
* @date:2022/6/23 20:24
*/
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
//1.创建BossGroup和WorkerGroup
//说明:创建了两个线程组,BossGroup和WorkerGroup
// 1.BossGroup 只是处理连接请求,真正的与客户端业务处理会交给WorkGroup处理
// 2.这两个都是无限循环
// 3.BossGroup和WorkerGroup 含有的子线程(NioEventLoop)的个数默认是CPU的核数乘2,在不指定的情况下
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//2.创建服务器端对象 配置启动参数
ServerBootstrap bootstrap = new ServerBootstrap();
//3.使用链式变成设置启动参数
//设置两个线程组
bootstrap.group(bossGroup, workerGroup)
//使用NioServerSocketChannel作为服务器的通道实现
.channel(NioServerSocketChannel.class)
//设置线程队列等待连接个数
.option(ChannelOption.SO_BACKLOG, 128)
//设置保持活动连接状态
.childOption(ChannelOption.SO_KEEPALIVE, true)
//创建一个通道初始化对象 并给WorkGroup的 EventLoop 对应的管道设置处理器 可以是Netty提供的 也可以是自定义的
.childHandler(new ChannelInitializer<SocketChannel>() {
//给WorkGroup关联的pipeline(管道)设置处理器
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//返回这个SocketChannel对应的pipeline
ChannelPipeline pipeline = ch.pipeline();
//像管道的最后增加一个处理器 处理业务
pipeline.addLast(new NettyServerHandle());
}
});
System.out.println("服务器已就绪");
//4.绑定一个端口并且同步处理,生成了一个ChannelFuture对象
//启动服务器(并绑定端口)
ChannelFuture cf = bootstrap.bind(6668).sync();
//5.对关闭通道事件进行监听
cf.channel().closeFuture().sync();
} finally {
//关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
NettyServerHandle
package com.netty.simple;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil;
/**
* @Description: WorkGroup的 EventLoop 对应的管道处理器
* @author: Freedom
* @QQ: 1556507698
* @date:2022/6/23 20:48
* 1.自定义一个Handle,需要继承Netty 规定好的 HandlerAdapter 即Handler适配器
* 2.这时我们自定义的Handler,才能成为一个Handler
*/
public class NettyServerHandle extends ChannelInboundHandlerAdapter {
/**
* 读取数据事件(这里可以读取客户端发送的消息)
* ChannelHandlerContext ctx 上下文对象 含有 管道pipeline (可以理解为业务处理),通道Channel(可以理解为数据读取),地址
* Object msg 客户端发送的数据,默认是Object对象
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Server ctx = " + ctx);
//将msg转成ByteBuf
//ByteBuf 是Netty 提供的, 不是 NIO 提供的 ByteBuffer
ByteBuf buf = (ByteBuf) msg;
//将消息转为UTF-8
System.out.println("客户端发送消息是:" + buf.toString(CharsetUtil.UTF_8));
//获取地址
System.out.println("客户端地址是:" + ctx.channel().remoteAddress());
//ctx pipeline channel 关系
}
/**
* 数据读取完毕,回复消息
*
* @param ctx
* @throws Exception
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//将数据写道一个缓存同时刷新该缓存 write+Flush
//对数据进行一个编码,然后放到buffer里面去,然后发出去
ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端 我是Server", CharsetUtil.UTF_8));
}
/**
* 处理异常 一般需要关闭通道
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("发生异常通道关闭");
ctx.channel().close();
}
}
netty Client
package com.netty.simple;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @Description: ·netty客户端
* @author: Freedom
* @QQ: 1556507698
* @date:2022/6/23 21:10
*/
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
//1.客户端需要一个事件循环组
NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
//2.创建一个客户端启动对象进行配置
Bootstrap bootstrap = new Bootstrap();
//设置线程组
bootstrap.group(eventExecutors)
//设置客户端通道的实现类(反射)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
//初始通道
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//加入自己的处理器
ch.pipeline().addLast(new NettyClientHandle());
}
});
System.out.println("客户端已就绪");
//3.启动客户端取连接服务器端 sync让这个方法不会阻塞在这里
//ChannelFuture 涉及到netty的异步模型
ChannelFuture sync = bootstrap.connect("127.0.0.1", 6668).sync();
//4.对关闭通道事件进行监听
sync.channel().closeFuture().sync();
} finally {
eventExecutors.shutdownGracefully();
}
}
}
NettyClientHandle
package com.netty.simple;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @Description: netty客户端处理器
* @author: Freedom
* @QQ: 1556507698
* @date:2022/6/23 21:25
*/
public class NettyClientHandle extends ChannelInboundHandlerAdapter {
/**
* 当通道就绪时 就会触发该方法 可以发消息了
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client ctx " + ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello,Server:我是client", CharsetUtil.UTF_8));
}
/**
* 当通道有读取事件时会触发 事件驱动
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//转换为netty提供的buf
ByteBuf buf = (ByteBuf) msg;
//转换为字符串并指定编码
System.out.println("服务器回复的消息:" + buf.toString(CharsetUtil.UTF_8));
System.out.println("服务器的地址:" + ctx.channel().remoteAddress());
}
/**
* 异常时触发此方法
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
POM 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.netty</groupId>
<artifactId>Netty-TCP</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.51.Final</version>
</dependency>
</dependencies>
</project>