一个简单的netty测试,类似聊天。client发送 聊天信息,server 回复client说的话。
运行效果:
client
service
1,引用jar包
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty-all.version}</version>
</dependency>
2,client 客户端
client.java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public final class Client {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
//Bootstrap :一个 Netty 应用通常由一个 Bootstrap 开始,主要作用是配置整个 Netty 程序,串联各个组件.
// Netty 中 Bootstrap 类是客户端程序的启动引导类,ServerBootstrap 是服务端启动引导类。
Bootstrap b = new Bootstrap();
//EventLoopGroup :主要管理 eventLoop 的生命周期,可以理解为一个线程池,内部维护了一组线程,
// 每个线程(NioEventLoop)负责处理多个 Channel 上的事件,而一个 Channel 只对应于一个线程
b.group(group)
.channel(NioSocketChannel.class)
//配置 处理 Channel【 I/O 事件或拦截 I/O 】的处理器
.handler(new ClientInitializer());
//Channel : Netty 网络通信的组件,能够用于执行网络 I/O 操作
Channel ch = b.connect("127.0.0.1", 8888).sync().channel();
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (; ; ) {
String line = in.readLine();
if (line == null) {
break;
}
// 给服务器发送信息
lastWriteFuture = ch.writeAndFlush(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if ("bye".equals(line.toLowerCase())) {
ch.closeFuture().sync();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
} finally {
group.shutdownGracefully();
}
}
}
ClientInitializer.java 设置Channel的Handler集合
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class ClientInitializer extends ChannelInitializer<SocketChannel> {
private static final StringDecoder DECODER = new StringDecoder();
private static final StringEncoder ENCODER = new StringEncoder();
private static final ClientHandler CLIENT_HANDLER = new ClientHandler();
@Override
public void initChannel(SocketChannel ch) {
//ChannelPipline : 保存 ChannelHandler 的 List,用于处理或拦截 Channel 的入站事件和出站操作。
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
// DECODER : IO 的 入站解码器
pipeline.addLast(DECODER);
// DECODER : IO 的 出站编码器
pipeline.addLast(ENCODER);
//添加自定义的 Channel 处理器 ClientHandler
pipeline.addLast(CLIENT_HANDLER);
}
}
ClientHandler.java 自定义Handler,接受server返回的信息并处理
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
@Sharable
public class ClientHandler extends SimpleChannelInboundHandler<String> {
/**
* 接受server返回的信息
*
* @param ctx 保存 Channel 相关的所有上下文信息,同时关联一个 ChannelHandler 对象。
* @param msg 信息
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.err.println(msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
2,server服务器
Server.java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public final class Server {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//ServerBootstrap 是服务端启动引导类,主要作用是配置整个 Netty 程序,串联各个组件
ServerBootstrap b = new ServerBootstrap();
//boosGroup 用于 Accetpt client连接建立事件并分发请求
//workerGroup workerGroup 用于处理 I/O 读写事件和业务逻辑
b.group(bossGroup, workerGroup)
//Channel : Netty 网络通信的组件,能够用于执行网络 I/O 操作
.channel(NioServerSocketChannel.class)
//打印日志
.handler(new LoggingHandler(LogLevel.INFO))
// 配置入站、出站事件handler
.childHandler(new ServerInitializer());
ChannelFuture f = b.bind(8888);
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2,ServerInitializer.java 配置入站、出站事件handler集合
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
private static final StringDecoder DECODER = new StringDecoder();
private static final StringEncoder ENCODER = new StringEncoder();
private static final ServerHandler SERVER_HANDLER = new ServerHandler();
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加 文本行编解码
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
// DECODER : IO 的 入站解码器
pipeline.addLast(DECODER);
// DECODER : IO 的 出站编码器
pipeline.addLast(ENCODER);
// 添加自己的 ServerHandler
pipeline.addLast(SERVER_HANDLER);
}
}
3,ServerHandler 自定义Handler,用于处理client发送来的信息
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.net.InetAddress;
import java.util.Date;
@Sharable
public class ServerHandler extends SimpleChannelInboundHandler<String> {
/**
* 新链接接通时
*
* @param ctx 保存 Channel 相关的所有上下文信息,同时关联一个 ChannelHandler 对象。
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 为新连接发送庆祝
ctx.write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n");
ctx.write("It is " + new Date() + " now.\r\n");
ctx.flush();
}
/**
* 接受client的信息
*
* @param ctx 保存 Channel 相关的所有上下文信息,同时关联一个 ChannelHandler 对象。
* @param request client的请求
* @throws Exception
*/
@Override
public void channelRead0(ChannelHandlerContext ctx, String request) throws Exception {
// Generate and write a response.
String response;
boolean close = false;
if (request.isEmpty()) {
response = "Please type something.\r\n";
} else if ("bye".equals(request.toLowerCase())) {
response = "Have a good day!\r\n";
close = true;
} else {
response = "Did you say '" + request + "'?\r\n";
}
ChannelFuture future = ctx.write(response);
if (close) {
future.addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
想更详细了解netty,推荐文章:https://www.cnblogs.com/imstudy/p/9908791.html