From:https://liudongdong1.github.io/
Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。是一个NIO客户端服务器框架,可以快速轻松地开发协议服务器和客户端等网络应用程序。它极大地简化并简化了TCP和UDP套接字服务器等网络编程。Netty经过精心设计,具有丰富的协议,如FTP,SMTP,HTTP以及各种二进制和基于文本的传统协议。
1. 代码编写绿色的部分Core核心模块,包括零拷贝、API库、可扩展的事件模型。
橙色部分Protocol Support协议支持,包括Http协议、webSocket、SSL(安全套接字协议)、谷歌Protobuf协议、zlib/gzip压缩与解压缩、Large File Transfer大文件传输等等。
红色的部分Transport Services传输服务,包括Socket、Datagram、Http Tunnel等等。
代码模块主要分为服务端和客户端。 主要实现的业务逻辑: 服务端启动成功之后,客户端也启动成功,这时服务端会发送一条信息给客户端。客户端或者telnet发送一条信息到服务端,服务端会根据逻辑回复客户端一条客户端,当客户端或者telent发送bye给服务端,服务端和客户端断开链接。
netty-helloworld
├── client
├── Client.class -- 客户端启动类
├── ClientHandler.class -- 客户端逻辑处理类
├── ClientInitializer.class -- 客户端初始化类
├── server
├── Server.class -- 服务端启动类
├── ServerHandler -- 服务端逻辑处理类
├── ServerInitializer -- 服务端初始化类
.1. 服务器端代码
.1. Server 入口
public final class Server {
public static void main(String[] args) throws Exception {
//Configure the server
//创建两个EventLoopGroup对象
//创建boss线程组 用于服务端接受客户端的连接
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// 创建 worker 线程组 用于进行 SocketChannel 的数据读写
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 创建 ServerBootstrap 对象
ServerBootstrap b = new ServerBootstrap();
//设置使用的EventLoopGroup
b.group(bossGroup,workerGroup)
//设置要被实例化的为 NioServerSocketChannel 类
.channel(NioServerSocketChannel.class)
// 设置 NioServerSocketChannel 的处理器
.handler(new LoggingHandler(LogLevel.INFO))
// 设置连入服务端的 Client 的 SocketChannel 的处理器
.childHandler(new ServerInitializer());
// 绑定端口,并同步等待成功,即启动服务端
ChannelFuture f = b.bind(8888);
// 监听服务端关闭,并阻塞等待
f.channel().closeFuture().sync();
} finally {
// 优雅关闭两个 EventLoopGroup 对象
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
.2. ServerInitializer
使用Netty编写业务层的代码,我们需要继承ChannelInboundHandlerAdapter 或SimpleChannelInboundHandler类
- 继承SimpleChannelInboundHandler类之后,会在接收到数据后会自动release掉数据占用的Bytebuffer资源。并且继承该类需要指定数据格式。
- 继承ChannelInboundHandlerAdapter则不会自动释放,需要手动调用**ReferenceCountUtil.release()**等方法进行释放。继承该类不需要指定数据格式。 (可以防止数据未处理完就被释放了)
public class ServerInitializer extends ChannelInitializer.3. ServerHandler{ 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())); // 解码和编码,应和客户端一致 pipeline.addLast(DECODER); pipeline.addLast(ENCODER); // 业务逻辑实现类 pipeline.addLast(SERVER_HANDLER); } }
@Sharable public class ServerHandler extends SimpleChannelInboundHandler.2. 客户端代码{ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 为新连接发送庆祝 ctx.write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!rn"); ctx.write("It is " + new Date() + " now.rn"); ctx.flush(); } //业务逻辑处理 @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.rn"; } else if ("bye".equals(request.toLowerCase())) { response = "Have a good day!rn"; close = true; } else { response = "Did you say '" + request + "'?rn"; } 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(); } }
.1. ClientInitializer客户端过滤其这块基本和服务端一致。不过需要注意的是,传输协议、编码和解码应该一致。
public class ClientInitializer extends ChannelInitializer.2. ClientHandler 业务处理逻辑{ 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) { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new DelimiterbasedframeDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast(DECODER); pipeline.addLast(ENCODER); pipeline.addLast(CLIENT_HANDLER); } }
@Sharable public class ClientHandler extends SimpleChannelInboundHandler{ //打印读取到的数据 @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(); } }



