关于netty
netty 是一个非阻塞IO框架,用于Java网络应用开发,特点是异步处理,并发处理能力,netty里面包含有reactor框架的实现,是一个非常高级的框架体系。
netty特性
netty 处理快,更少的资源需求,响应快,可以作为高并发场景服务器的一个选择
reactor 个人理解是 react:响应式, or :对象,就是响应式框架,netty 就是运用reactor 的核心设计思想编写的高性能高并发网络请求处理器框架。
以下来自维基百科,自由的百科全书
注意:本条目主题可能尚无中文译名,因而使用原文或其拉丁字母转写作为标题。如果您在可靠来源中找到本主题的中文名称,请勇于将其移动至中文标题。(2019年2月)
开发者 | Netty项目社区 |
稳定版本 | 4.1.31.Final[1](2018年10月30日,2年前) |
预览版本 | 5.0.0.Alpha3(2016年1月14日,5年前) |
源代码库 | github.com/netty/netty |
编程语言 | Java |
类型 | Enterprise Integration Patterns Message Oriented Middleware |
许可协议 | Apache许可证 2.0 |
网站 | netty.io |
Netty是一个非阻塞I/O客户端-服务器框架,主要用于开发Java网络应用程序,如协议服务器和客户端。异步事件驱动的网络应用程序框架和工具用于简化网络编程,例如TCP和UDP套接字服务器。[2]Netty包括了反应器编程模式的实现。Netty最初由JBoss开发,现在由Netty项目社区开发和维护。
除了作为异步网络应用程序框架,Netty还包括了对HTTP、HTTP2、DNS及其他协议的支持,涵盖了在Servlet容器内运行的能力、对WebSockets的支持、与Google Protocol Buffers的集成、对SSL/TLS的支持以及对用于SPDY协议和消息压缩的支持。自2004年以来,Netty一直在被积极开发。[3]
从版本4.0.0开始,Netty在支持NIO和阻塞Java套接字的同时,还支持使用NIO.2作为后端。
用netty写一个简单非阻塞请求响应服务器
简单示意代码
服务端
服务器 HttpServer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package net.narule.jnetty.httpdemo;
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;
import java.net.InetSocketAddress;
/**
* netty server
*/
public class HttpServer {
int port ;
public HttpServer(int port){
this.port = port;
}
public void start() throws Exception{
ServerBootstrap bootstrap = new ServerBootstrap();
// 事件监听相关对象配置 netty 循环监听是否有新事件
// 如果有 马上将事件交给处理器,处理器层层循环处理,会循环到自定义消息解析器 HttpRequestHandler
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup work = new NioEventLoopGroup();
bootstrap.group(boss,work)
.handler(new LoggingHandler(LogLevel.DEBUG))
.channel(NioServerSocketChannel.class)
.childHandler(new HttpServerInitializer());
ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
System.out.println("server start... port : " + port);
f.channel().closeFuture().sync();
}
}
请求处理器初始化 HttpServerInitializer
initChannel 处理器配置。可以配置多个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package net.narule.jnetty.httpdemo;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// http 编解码
pipeline.addLast(new HttpServerCodec());
// http 消息聚合器 512*1024为接收的最大contentlength
pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024));
// 请求处理器
pipeline.addLast(new HttpRequestHandler());
}
}
消息处理器 HttpRequestHandler
重写channelRead0 方法处理请求的消息并返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package net.narule.jnetty.httpdemo;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
// 处理数据
Date date = new Date(System.currentTimeMillis());
String uri = req.uri();
Map<String,String> data = new HashMap<>();
String protocal = req.protocolVersion().text(); //获取HTTP协议版本
String content = req.content().toString(CharsetUtil.UTF_8); //获取HTTP协议版本
System.out.println("request uri:" + uri);
System.out.println("request content:" + content);
boolean match = false;
if(uri.contains("J")) {
match = true;
}
data.put("match", String.valueOf(match));
data.put("protocal", protocal);
data.put("uri", uri);
data.put("time", date.toString());
data.put("content", content);
System.getProperty("HOST");
String responsedata = "{";
Set<String> keySet = data.keySet();
int size = data.size();
for (String key : keySet) {
size --;
responsedata = responsedata + "\"" + key + "\":" + "\"" + data.get(key) + (size == 0? "\"}" : "\",");
}
// 创建http响应
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.copiedBuffer(responsedata, CharsetUtil.UTF_8));
// 设置头信息
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
// 将处理后的数据 write到客户端、
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
启动
main方法启动服务
1
2
3
4
public static void main(String[] args) throws Exception{
HttpServer server = new HttpServer(80);// 80为启动端口
server.start();
}
1
server start... port : 80
客户端测试
浏览器发送请求
直接url栏输入get请求:
1
http://localhost/test?name=J&time=-1
返回结果
1
2
3
4
5
6
7
{
"match":"true",
"time":"Sun Jul 11 21:52:22 CST 2021",
"protocal":"HTTP/1.1",
"uri":"/test?name=J&time=-1",
"content":""
}
发送请求
1
http://localhost/test?name=nos&time=-1
返回结果
1
2
3
4
5
6
7
{
"match":"false",
"time":"Sun Jul 11 21:52:22 CST 2021",
"protocal":"HTTP/1.1",
"uri":"/test?name=nos&time=-1",
"content":""
}