Netty 实战- Netty 的概念及体系结构

Netty 的概念及体系结构

Netty–异步和事件驱动

 Netty 提供了极丰富的网络编程工具集,但其只是一个框架,它的架构方法和设计原则是:每一个笑点都和它的技术内容一样重要。

  • 关注点分离—-业务和网络逻辑解耦
  • 模块化和可复用性
  • 可测试性味首要的要求

Java 网络编程

    早期的 Java API(java.net)只支持本地系统的套接字库来提供所谓的阻塞函数。

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
67
68
69
70
71
72
73
74
75
76
77

package nia.chapter1;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.ServerSocket;

import java.net.Socket;

public class BlockingIoExample {

/**

* 代码清单 1-1 阻塞 I/O 示例

* */

public void serve(int portNumber) throws IOException {

//创建一个新的 ServerSocket,用以监听指定端口上的连接请求

ServerSocket serverSocket = new ServerSocket(portNumber);

//对accept()方法的调用将被阻塞,直到一个连接建立

Socket clientSocket = serverSocket.accept();

//这些流对象都派生于该套接字的流对象

BufferedReader in = new BufferedReader(

new InputStreamReader(clientSocket.getInputStream()));

PrintWriter out =

new PrintWriter(clientSocket.getOutputStream(), true);

String request, response;

//处理循环开始

while ((request = in.readLine()) != null) {

if ("Done".equals(request)) {

break;

}

//请求被传递给服务器的处理方法

response = processRequest(request);

//服务器的响应被发送给了客户端

out.println(response);

//继续执行处理循环

}

}

private String processRequest(String request){

return "Processed";

}

}

Java NIO

Java 对非阻塞I/O的支持在JDK1.4的 java.nio包中。

选择器

java.nio.channels.Selector 是Java的非阻塞I/O实现的关键。使用了事件通知API以确定一组非阻塞套接字中农有哪些已经就绪能够进行I/O相关操作。

  • 使用较少的县城可以处理许多连接,因此也减少了内存管理和上下文切换带来的开销
  • 当没有I/O操作需要的时候,线程可以用于其他任务

Netty 简介

 想要实现更高的吞吐量和可扩展性,在更低的成本基础上进行交付。如果直接使用底层的API,显得较为复杂。在网络编程领域,Netty是 Java的卓越框架。它驾驭了Java高级API的能力,并将其隐藏在一个易于使用的API之后。其特性主要体现在以下。

  • 设计:统一的API,支持多种传输类型,阻塞和非阻塞,简单而强大的线程模型,真正的无连接数据报套接字支持,链接逻辑组建以支持复用
  • 易于使用:详实的文档和示例集
  • 性能:拥有比Java的核心API更高的吞吐量以及更低的延迟,得益于池化和复用,拥有更低的资源消耗,最少的内存复制
  • 健壮性:不会因为慢速、快速或者超载的连接导致OutOfMemoryError
  • 安全性:完整的SSL/TLS支持
  • 社区驱动:发布快速且频繁

异步和事件驱动

异步和可伸缩性之间的联系:

  • 非阻塞网络调用使我们可以不必等待一个操作的完成。完全异步的I/O正是基于这个特性构建的,异步方法会立即返回,并且在它完成时,会直接或者稍后的某个时间通知用户。
  • 选择器是的我们能够通过较少的线程见识许多连接上的事件

Netty 的核心组件

  • Channel
  • 回调
  • Future
  • 事件和ChannelHandler

这些构建块代表了不同类型的构造:资源、逻辑以及通知。你的应用将使用它们来访问网络以及流经网络的数据。

Channel

Channel 是Java NIO 的一个基本构造。代表了一个实体的开放连接,如读操作和写操作。

回调

回调其实就是一个方法,一个指向已经被提供给另一个方法的方法的引用。回调在广泛的编程场景中都有应用,而且是在操作完成后通知相关方最常见的方式。在Netty内部使用了回调来处理事件,当一个回调被触发时,相关事件可以被 ChannelHandler 接口实现来处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.ChannelInboundHandlerAdapter;

public class ConnectHandler extends ChannelInboundHandlerAdapter {

@Override

//当一个新的连接已经被建立时,channelActive(ChannelHandlerContext)将会被调用

public void channelActive(ChannelHandlerContext ctx)

throws Exception {

System.out.println(

"Client " + ctx.channel().remoteAddress() + " connected");

}

}

Future

Future 提供了另一种在操作完成时通知应用程序的方式。可以看做是异步操作的结果占位符;它将在未来的某个时刻完成,并提供对其结果的访问。每个 Netty 的出站I/O操作都返回一个ChannelFuture,也就是说都不会阻塞。

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
67
68
69
70
71
72
73
74
75
76
77

import io.netty.buffer.ByteBuf;

import io.netty.buffer.Unpooled;

import io.netty.channel.Channel;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelFutureListener;

import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;

import java.nio.charset.Charset;

public class ConnectExample {

private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel();

public static void connect() {

Channel channel = CHANNEL_FROM_SOMEWHERE; //reference form somewhere

// Does not block

//异步地连接到远程节点

ChannelFuture future = channel.connect(

new InetSocketAddress("192.168.0.1"25));

//注册一个 ChannelFutureListener,以便在操作完成时获得通知

future.addListener(new ChannelFutureListener() {

@Override

public void operationComplete(ChannelFuture future) {

//检查操作的状态

if (future.isSuccess()) {

//如果操作是成功的,则创建一个 ByteBuf 以持有数据

ByteBuf buffer = Unpooled.copiedBuffer(

"Hello", Charset.defaultCharset());

//将数据异步地发送到远程节点。返回一个 ChannelFuture

ChannelFuture wf = future.channel()

.writeAndFlush(buffer);

// ...

else {

//如果发生错误,则访问描述原因的 Throwable

Throwable cause = future.cause();

cause.printStackTrace();

}

}

});

}

}

事件和 ChannelHandler

Netty 使用不同的事件通知我们状态的改变或者是操作的改变。使我们能够基于已经发生的事件来触发适当的动作。如:

  • 记录日志
  • 数据转换
  • 流控制
  • 应用程序逻辑

Netty 入站数据或者相关的状态变更而触发的事件包括:

  • 连接已被激活或连接失活
  • 数据读取
  • 用户事件
  • 错误事件

Netty 出站事件是未来将会触发的某个动作的操作结果,如:

  • 打开或关闭到远程节点的连接
  • 将数据写到或者冲刷到套接字
作者

Zachary Darius

发布于

2021-08-03

更新于

2021-08-03

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×