一、Netty是什么
Netty是JBOSS开源的一款NIO网络编程框架,可用于快速开发网络的应用。Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发高性能的服务端和客户端。可以极大的简化基于TCP、UDP等协议的网络服务。并且Netty对于各种传输类型(阻塞或非阻塞式的socket)、通信方式(HTTP或websocket)都提供了统一的API接口,提供了灵活的可扩展性,高度可自定义的线程模型(多线程、线程池等),支持使用无连接的数据报UDP进行通信,具有高吞吐量、低延迟、资源消耗低、最低限度的内存复制等特性。除了优越的性能外,Netty还支持SSL/TLS和StartTLS等加密传输协议,保证了数据传输的安全性。
在实际使用时,Netty可以作为Socket编程的中间件;也可以和Protobuf技术结合使用,实现一个RPC框架,实现远程过程调用;也可以作为一个websocket的长链接服务器,实现客户端和服务端的长连接通信。
二、Hello Netty
使用Netty作为一个Web服务器,用于接收用户请求并给出响应。
Netty程序一般都是按套路来写,依次编写主程序类、自定义初始化器、自定义处理器。
1、主程序类MyNettyServerTest
通过ServerBootstrap注册serverGroup和clientGroup两个事件循环组,其中serverGroup用于获取客户端连接,clientGroup用于处理客户端连接,类似于常见的Master-Slave结构。
2、初始化器MyNettyServerInitializer
继承Netty提供的初始化器ChannelInitializer。
Netty封装了各种各样的内置处理器,用于实现各种功能。并且ChannelInitializer的initChannel()方法会在某一个连接注册到Channel后立即被触发调用。因此,可以根据业务需求,在initChannel()中添加若干个Netty内置处理器,利用Netty强大的类库直接处理大部分业务。最后再在initChannel()中添加一个自定义处理器,用于实现特定业务的具体功能。
3、自定义处理器MyNettyServerHandler
继承SimpleChannelInboundHandler,该父类的channelRead0()方法可以接收客户端的所有请求,并作出响应,输出“Hello Netty”。
简单讲,Netty程序就是通过主程序类关联自定义初始化器,然后在初始化器中加入Netty内置处理器和自定义处理器,最后在自定义处理器中编写处理特定需求的业务代码。
三、代码实例
1、maven中加入netty-all
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.68.Final</version>
</dependency>
2、主程序类MyNettyServerTest
package com.guor.demo.netty;
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;
public class MyNettyServerTest {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup serverGroup = new NioEventLoopGroup();
EventLoopGroup clientGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
ChannelFuture channelFuture = serverBootstrap.group(serverGroup, clientGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new MyNettyServerInitializer()).bind(8080).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
System.out.println(e);
}finally {
serverGroup.shutdownGracefully();
clientGroup.shutdownGracefully();
}
}
}
3、初始化器MyNettyServerInitializer
package com.guor.demo.netty;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
public class MyNettyServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("HttpServerCodec",new HttpServerCodec());
pipeline.addLast("MyNettyServerHandler",new MyNettyServerHandler());
}
}
4、自定义处理器MyNettyServerHandler
package com.guor.demo.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8);
DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
byteBuf.readableBytes();
channelHandlerContext.writeAndFlush(defaultFullHttpResponse);
}
}
5、通过curl http://localhost:8080访问Netty服务
此时,可能会提示curl不是内部或外部命令 ,如何解决?
四、curl不是内部或外部命令
1、下载curl for 64-bit
https://curl.se/windows/
2、将zip解压到文件夹
3、在环境变量中配置
五、重写SimpleChannelInboundHandler中一些重要的回调方法
1、重写回调方法
package com.guor.demo.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8);
DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
byteBuf.readableBytes();
channelHandlerContext.writeAndFlush(defaultFullHttpResponse);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception{
System.out.println("1、handlerAdded、增加了新的处理器");
super.handlerAdded(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
System.out.println("2、channelRegistered、通道被注册");
super.channelRegistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
System.out.println("3、channelActive、通道连接到了远端,处于活跃状态");
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception{
System.out.println("4、channelInactive、通道远端断开了连接,处于非活跃状态");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{
System.out.println("5、channelUnregistered、通道被取消了注册");
super.channelUnregistered(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,Throwable e) throws Exception{
System.out.println("6、exceptionCaught、程序发生了异常");
e.printStackTrace();
ctx.close();
}
}
2、通过curl http://localhost:8080访问Netty服务
3、控制台输出
4、ctrl + c停止访问
Java高并发编程实战系列文章
Java高并发编程实战1,那些年学过的锁
Java高并发编程实战2,原子性、可见性、有序性,傻傻分不清
Java高并发编程实战3,Java内存模型与Java对象结构
Java高并发编程实战4,synchronized与Lock底层原理
Java高并发编程实战5,异步注解@Async自定义线程池
哪吒精品系列文章
Java学习路线总结,搬砖工逆袭Java架构师
10万字208道Java经典面试题总结(附答案)
SQL性能优化的21个小技巧
Java基础教程系列
Spring Boot 进阶实战
|