文章目录
- 一、概述
- 1、简介
- 2、特点
- 3、Gradle
- 4、demo
一、概述
1、简介
Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。
客户端向服务端发送一个http请求,验证之后建立长连接,控制层接收请求业务层进行业务处理,产生数据之后返回这是使用websocket建立长连接的一个流程,而netty的作用就是将http请求发送出来的这些数据根据协议的规范,抽取出事件,形成回调方法去处理。
Spark也是对于netty的一种封装,就像SparkStreaming处理数据流的流程这样的目的就是对于事件有着高效处理的功能。
2、特点
设计
- 针对bio/nio指定了一个普通的api
- 基于灵活且可扩展的事件模型,可以清晰地分离关注点
- 高度可定制的线程模型 - 单线程,一个或多个线程池,如SEDA
- 真正的无连接数据报套接字支持(自3.1起)
使用
- 详细记录的Javadoc,用户指南和示例
性能
- 更高的吞吐量,更低的延迟
- 减少资源消耗
- 最小化不必要的内存复制
安全
- 完整的SSL\TLS和StartTLS支持
社区
- 发布时间早,且常更新
3、Gradle
Gradle类似于maven,区别是它更加灵活更加强大,但是和xml语言构建的maven不同,Gradle的语言是基于Groove的。
首先创建好依赖:
plugins {
id 'java'
}
group 'com.gongda'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
implementation(
'io.netty:netty-all:4.1.39.Final'
)
}
4、demo
通过netty实现一个简单的小案例,简单讲解一下流程:
- 首先创建一个异步事件循环组,一个负责连接,一个负责之后的业务处理
- 服务端在启动之前首先要进行配置,可以自定义也可以用封装好的配置
但无论如何,配置的文件都是在连接成功之后针对管道的配置,所以需要继承基础的初始化父类。
重写initChannel方法,创建管道拦截器配置
创建内部封装好的配置
也可以创建自定义的拦截器
在拦截器内部自己定义要实现的功能:
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;
import java.net.URI;
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
System.out.println(msg.getClass());
System.out.println(ctx.channel().remoteAddress());
Thread.sleep(8000);
if (msg instanceof HttpRequest){
HttpRequest httpRequest = (HttpRequest)msg;
System.out.println("请求方法名" + httpRequest.method().name());
URI uri = new URI(httpRequest.uri());
if ("/favicon.ico".equals(uri.getPath())){
System.out.println("请求favicon.ico");
return;
}
ByteBuf context = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, context);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, context.readableBytes());
ctx.writeAndFlush(response);
ctx.channel().close();
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel Active");
super.channelActive(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel Registered");
super.channelRegistered(ctx);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("handler Added");
super.handlerAdded(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel Inactive");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel Unregistered");
super.channelUnregistered(ctx);
}
}
- Server端将自定义的初始化配置操作添加进来,绑定端口
- 结束之后进行回收
调用了一个HttpServletCodec,它是内部封装好的一个拦截器配置,作用十分强大,对于http请求进行编解码进行字节码的转换。
另外,还有一点需要注意Netty和SpringMVC甚至和SpringBoot都是有很大区别的,因为Netty所负责的业务功能,都被SpringBoot封装好了,就像域名匹配、端口转发,但是我们使用Netty的原因更多是为了并发,所以Netty是一个比较底层的框架,甚至没有端口映射、域名匹配的封装 。
- 创建一个客户端与服务端互通
Server端差不多在Client端要实现的就是连接,并且可以做到端口映射、现互通。
模型其实都是和Server端差不多的。
先创建线程模型,然后创建连接的配置:
同样也需要一个客户端的初始化去做拦截器和服务端是一样的。
控制器决定连接之后做什么:
public class MyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(ctx.channel().remoteAddress());
System.out.println("client output" + msg);
ctx.writeAndFlush("from Client" + LocalDateTime.now());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("客户端");
}
}
然后注意的是,我们要将之前的http请求的信息种类改成String的种类,并且在两个端的拦截器去除掉httpServerCodec的拦截,不然不会打印出信息的。