依赖
<!--netty-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
服务端代码
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
//设置main方法日志级别
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
List<Logger> loggerList = loggerContext.getLoggerList();
loggerList.forEach(logger -> {
logger.setLevel(Level.WARN);
});
//1.创建BossGroup 和 WorkerGroup
//说明:
//创建两个线程组 bossGroup和workerGroup
//bossGroup只是处理连接请求
//workerGroup真正的和客户端进行业务处理
//两个都是无限循环
//默认bossGroup和workerGroup含有的子线程(NioEventLoop)的个数=2*CPU核数
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//2.创建服务器端的启动对象,配置参数
ServerBootstrap serverBootstrap = new ServerBootstrap();
//3.使用链式编程进行设置
serverBootstrap
//设置两个线程组
.group(bossGroup,workerGroup)
//使用NioServerSocketChannel作为服务器的通道实现
.channel(NioServerSocketChannel.class)
//设置线程队列等待连接个数
.option(ChannelOption.SO_BACKLOG,128)
//设置保持活动连接状态
.childOption(ChannelOption.SO_KEEPALIVE,true)
//给我们的workerGroup的EventLoopGroup对应的管道设置处理器Handler
.childHandler(
//创建一个通道初始化对象(匿名对象)
new ChannelInitializer<SocketChannel>() {
//给管道设置处理器
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("...服务器 is ready ...");
//4.绑定一个端口并且同步,生成一个ChannelFuture对象
//启动服务器并绑定端口
ChannelFuture sync = serverBootstrap.bind(6668).sync();
//5.对关闭通道进行监听
sync.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
服务端Handler
:
/**
* 说明:
* 1.自定义一个Handler,需要继承netty规定好的某个Handler适配器
* 2.这时我们自定义一个handler,才能称为一个handler
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* 读取数据事件(可以读取客户端发送的消息)
* 1.ChannelHandlerContext:上下文对象,含有管道pipeline,通道channel,地址。
* 管道和通道区别:管道里面是处理器(处理数据),通道里面是buffer写入的数据(传输数据)
*2.msg: 客户端发送的数据
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("server ctx="+ctx);
//将msg转成一个ByteBuf
//这个ByteBuf是netty提供的,不是nio的ByteBuffer
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("客户端发送的消息是:"+byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("客户端地址:"+ctx.channel().remoteAddress());
}
/**
* 数据读取完毕
* 发送消息给客户端
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//writeAndFlush是write+flush
//将数据写入到缓存,并刷新
//一般来讲,我们对这个发送的数据进行编码
ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端~",CharsetUtil.UTF_8));
}
/**
* 异常处理,一般需要关闭通道
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
//也可以
// ctx.channel().close();
}
}
客户端
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
//设置main方法日志级别
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
List<Logger> loggerList = loggerContext.getLoggerList();
loggerList.forEach(logger -> {
logger.setLevel(Level.WARN);
});
//客户端需要一个事件循环组
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
//创建客户端启动对象
//注意客户端使用的不是serverBootStrap而是BootStrap
Bootstrap bootstrap = new Bootstrap();
//设置相关参数
bootstrap
//设置线程组
.group(eventExecutors)
//客户端通道的实现类(反射)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//加入自己的处理器
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("客户端...ok...");
//启动客户端去连接服务端
//关于ChannelFuture后面会分析,设计netty的异步模型
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync();
//给关闭通道进行监听
channelFuture.channel().closeFuture().sync();
} finally {
eventExecutors.shutdownGracefully();
}
}
}
客户端Handler
:
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
//当通道就绪就会触发该方法
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client "+ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello,server :瞄", CharsetUtil.UTF_8));
}
//当通道有读取事件时,会触发
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("服务器回复的消息:"+buf.toString(CharsetUtil.UTF_8));
System.out.println("服务器的地址:"+ctx.channel().remoteAddress());
}
//异常发生时的处理
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}