Netty是一个异步事件驱动的网络应用程序框架用于快速开发可维护的高性能协议服务器和客户端。
本人刚刚开始学习Netty框架,依靠网上资料尝试运行第一个Netty框架的项目(使用idea)
使用Java语言,在maven项目中,创建客户端和服务端
客户端
客户端启动类
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;
public class MyClient {
public static void main(String[] args) throws Exception {
//创建线程池eventExecutors
NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
//创建bootstrap对象,配置参数
Bootstrap bootstrap = new Bootstrap();
//设置线程组
bootstrap.group(eventExecutors)
//设置客户端的通道实现类型
.channel(NioSocketChannel.class)
//使用匿名内部类初始化通道
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//添加客户端通道的处理器,通过addLast方法
ch.pipeline().addLast(new MyClientHandler());
}
});
System.out.println("客户端准备就绪");
//连接服务端
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6666).sync();
//对通道关闭进行监听
channelFuture.channel().closeFuture().sync();
} finally {
//关闭线程组
eventExecutors.shutdownGracefully();
}
}
}
这段Java代码实现了一个基于Netty框架的客户端程序。该程序采用异步事件驱动模型,使用NioEventLoopGroup线程池来处理数据读写操作。
在程序启动时,通过创建NioEventLoopGroup线程池eventExecutors来处理客户端I/O操作。然后通过创建Bootstrap对象,并设置相关参数,包括通道类型NioSocketChannel和初始化通道对象的匿名内部类。再使用addLast方法给管道添加MyClientHandler处理器,即客户端处理器。接着,打印客户端已经准备就绪的消息。
当客户端连接服务端成功后,会触发ChannelInitializer的initChannel方法,在该方法中给pipeline管道设置处理器,即MyClientHandler。该处理器主要实现了对服务端发送的消息进行处理并回应相应的响应消息,以及对异常情况进行处理。最后,在程序执行完毕后,通过shutdownGracefully()方法优雅地关闭线程组。
客户端处理器
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;
public class MyClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//发送消息到服务端
ctx.writeAndFlush(Unpooled.copiedBuffer("你好", CharsetUtil.UTF_8));
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//接收服务端发送过来的消息
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("收到服务端" + ctx.channel().remoteAddress() + "的消息:" + byteBuf.toString(CharsetUtil.UTF_8));
}
}
服务端
服务端启动类
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;
public class MyServer {
public static void main(String[] args) throws Exception {
//创建两个线程组 boosGroup、workerGroup。
//处理客户端连接请求
EventLoopGroup bossGroup = new NioEventLoopGroup();
//I/O处理任务
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//创建服务端的启动对象,设置参数
ServerBootstrap bootstrap = new ServerBootstrap();
//设置两个线程组boosGroup和workerGroup
bootstrap.group(bossGroup, workerGroup)
//设置服务端通道实现类型
.channel(NioServerSocketChannel.class)
//设置线程队列得到连接个数
.option(ChannelOption.SO_BACKLOG, 128)
//设置保持活动连接状态
.childOption(ChannelOption.SO_KEEPALIVE, true)
//使用匿名内部类的形式初始化通道对象
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//给pipeline管道设置处理器
socketChannel.pipeline().addLast((ChannelHandler) new MyServerHandler());
}
});//给workerGroup的EventLoop对应的管道设置处理器
System.out.println("java技术爱好者的服务端已经准备就绪...");
//绑定端口号,启动服务端
ChannelFuture channelFuture = bootstrap.bind(6666).sync();
//对关闭通道进行监听
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
这段Java代码实现了一个基于Netty框架的服务端程序。该程序采用异步事件驱动模型,使用NioEventLoopGroup线程池来处理客户端连接请求和数据读写操作。
在程序启动时,通过创建两个线程组bossGroup、workerGroup来分别处理客户端连接请求和I/O处理任务。然后通过创建ServerBootstrap对象,并设置相关参数,包括通道类型NioServerSocketChannel、线程队列连接数SO_BACKLOG、保持活动连接状态SO_KEEPALIVE等。接着,使用匿名内部类形式初始化通道对象,并设置管道处理器,即MyServerHandler。再绑定端口号6666,最后通过sync()方法同步等待服务器启动完成。
当客户端连接成功后,会触发ChannelInitializer的initChannel方法,在该方法中给pipeline管道设置处理器,即MyServerHandler。该处理器主要实现了对客户端发送的消息进行处理并回应相应的响应消息,以及对异常情况进行处理。最后,在程序执行完毕后,通过shutdownGracefully()方法优雅地关闭线程组。
服务端处理器
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;
/**
* 自定义的Handler需要继承Netty规定好的HandlerAdapter
* 才能被Netty框架所关联,有点类似SpringMVC的适配器模式
**/
public class MyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//获取客户端发送过来的消息
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("收到客户端" + ctx.channel().remoteAddress() + "发送的消息:" + byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//发送消息给客户端
ctx.writeAndFlush(Unpooled.copiedBuffer("服务端已收到消息,并给你发送一个问号?", CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//发生异常,关闭通道
ctx.close();
}
}
创建maven项目需添加依赖如下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
如果没有报错就可以启动了。
先启动服务端,再启动客户端
如果没有意外,启动服务端会有
java技术爱好者的服务端已经准备就绪...
然后启动客户端会有
客户端准备就绪
服务端会收到客户端的消息
收到客户端/127.0.0.1:54606发送的消息:你好
客户端
收到服务端/127.0.0.1:6666的消息:服务端已收到消息,并给你发送一个问号?