Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 92101f8

Browse files
committed
completed 实现
1 parent 74e0805 commit 92101f8

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

‎NETTY BY EXAMPLE/Implementation.md‎

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,233 @@ Listing 12.2 Implementation that handles HTTP
119119
10. Helper 方法生成了100 持续的响应,并写回给客户端
120120
11. 若执行阶段抛出异常,则关闭管道
121121

122+
这就是 Netty 处理标准的 HTTP 。你可能需要分别处理特定 URI ,应对不同的状态代码,这取决于资源存在与否,但基本的概念将是相同的。
123+
124+
我们的下一个任务将会提供一个组件来支持 SPDY 作为首选协议。
125+
Netty 提供了简单的处理 SPDY 方法。这些将使您能够重用FullHttpRequest 和 FullHttpResponse 消息,通过 SPDY 透明地接收和发送他们。
126+
127+
HttpRequestHandler 虽然是我们可以重用代码,我们将改变我们的内容写回客户端只是强调协议变化;通常您会返回相同的内容。下面的清单展示了实现,它扩展了先前的 HttpRequestHandler。
128+
129+
Listing 12.3 Implementation that handles SPDY
130+
131+
@ChannelHandler.Sharable
132+
public class SpdyRequestHandler extends HttpRequestHandler { //1
133+
@Override
134+
protected String getContent() {
135+
return "This content is transmitted via SPDY\r\n"; //2
136+
}
137+
}
138+
139+
1. 继承 HttpRequestHandler 这样就能共享相同的逻辑
140+
2. 生产内容写到 payload。这个重写了 HttpRequestHandler 的
141+
getContent() 的实现
142+
143+
SpdyRequestHandler 继承自 HttpRequestHandler,但区别是:写入的内容的 payload 状态的响应是在 SPDY 写的。
144+
145+
我们可以实现两个处理程序逻辑,将选择一个相匹配的协议。然而添加以前写过的处理程序到 ChannelPipeline 是不够的;正确的编解码器还需要补充。它的责任是检测传输字节数,然后使用 FullHttpResponse 和 FullHttpRequest 的抽象进行工作。
146+
147+
Netty 的附带一个基类,完全能做这个。所有您需要做的是实现逻辑选择协议和选择适当的处理程序。
148+
149+
清单12.4显示了实现,它使用 Netty 的提供的抽象基类。
150+
151+
public class DefaultSpdyOrHttpChooser extends SpdyOrHttpChooser {
152+
153+
public DefaultSpdyOrHttpChooser(int maxSpdyContentLength, int maxHttpContentLength) {
154+
super(maxSpdyContentLength, maxHttpContentLength);
155+
}
156+
157+
@Override
158+
protected SelectedProtocol getProtocol(SSLEngine engine) {
159+
DefaultServerProvider provider = (DefaultServerProvider) NextProtoNego.get(engine); //1
160+
String protocol = provider.getSelectedProtocol();
161+
if (protocol == null) {
162+
return SelectedProtocol.UNKNOWN; //2
163+
}
164+
switch (protocol) {
165+
case "spdy/2":
166+
return SelectedProtocol.SPDY_2; //3
167+
case "spdy/3.1":
168+
return SelectedProtocol.SPDY_3_1; //4
169+
case "http/1.1":
170+
return SelectedProtocol.HTTP_1_1; //5
171+
default:
172+
return SelectedProtocol.UNKNOWN; //6
173+
}
174+
}
175+
176+
@Override
177+
protected ChannelInboundHandler createHttpRequestHandlerForHttp() {
178+
return new HttpRequestHandler(); //7
179+
}
180+
181+
@Override
182+
protected ChannelInboundHandler createHttpRequestHandlerForSpdy() {
183+
return new SpdyRequestHandler(); //8
184+
}
185+
}
186+
187+
1. 使用 NextProtoNego 用于获取 DefaultServerProvider 的引用, 用于 SSLEngine
188+
2. 协议不能被检测到。一旦字节已经准备好读,检测过程将重新开始。
189+
3. SPDY 2 被检测到
190+
4. SPDY 3 被检测到
191+
5. HTTP 1.1 被检测到
192+
6. 未知协议被检测到
193+
7. 将会被调用给 FullHttpRequest 消息添加处理器。该方法只会在不支持 SPDY 时调用,那么将会使用 HTTPS
194+
8. 将会被调用给 FullHttpRequest 消息添加处理器。该方法在支持 SPDY 时调用
195+
196+
该实现要注意检测正确的协议并设置 ChannelPipeline 。它可以处理SPDY 版本 2、3 和 HTTP 1.1,但可以很容易地修改 SPDY 支持额外的版本。
197+
198+
### 设置 ChannelPipeline
199+
200+
通过实现 ChannelInitializer 将所有的处理器连接到一起。正如你所了解的那样,这将设置 ChannelPipeline 并添加所有需要的ChannelHandler 的。
201+
202+
SPDY 需要两个 ChannelHandler:
203+
204+
* SslHandler,用于检测 SPDY 是否通过 TLS 扩展
205+
* DefaultSpdyOrHttpChooser,用于当协议被检测到时,添加正确的 ChannelHandler 到 ChannelPipeline
206+
207+
除了添加 ChannelHandler 到 ChannelPipeline, ChannelInitializer 还有另一个责任;即,分配之前创建的 DefaultServerProvider 通过 SslHandler 到 SslEngine 。这将通过Jetty NPN 类库的 NextProtoNego helper 类实现
208+
209+
Listing 12.5 Implementation that handles SPDY
210+
211+
public class SpdyChannelInitializer extends ChannelInitializer<SocketChannel> { //1
212+
private final SslContext context;
213+
214+
public SpdyChannelInitializer(SslContext context) //2 {
215+
this.context = context;
216+
}
217+
218+
@Override
219+
protected void initChannel(SocketChannel ch) throws Exception {
220+
ChannelPipeline pipeline = ch.pipeline();
221+
SSLEngine engine = context.newEngine(ch.alloc()); //3
222+
engine.setUseClientMode(false); //4
223+
224+
NextProtoNego.put(engine, new DefaultServerProvider()); //5
225+
NextProtoNego.debug = true;
226+
227+
pipeline.addLast("sslHandler", new SslHandler(engine)); //6
228+
pipeline.addLast("chooser", new DefaultSpdyOrHttpChooser(1024 * 1024, 1024 * 1024));
229+
}
230+
}
231+
232+
1. 继承 ChannelInitializer 是一个简单的开始
233+
2. 传递 SSLContext 用于创建 SSLEngine
234+
3. 新建 SSLEngine,用于新的管道和连接
235+
4. 配置 SSLEngine 用于非客户端使用
236+
5. 通过 NextProtoNego helper 类绑定 DefaultServerProvider 到 SSLEngine
237+
6. 添加 SslHandler 到 ChannelPipeline 这将会在协议检测到时保存在 ChannelPipeline
238+
7. 添加 DefaultSpyOrHttpChooser 到 ChannelPipeline 。这个实现将会监测协议。添加正确的 ChannelHandler 到 ChannelPipeline,并且移除自身
239+
240+
实际的 ChannelPipeline 设置将会在 DefaultSpdyOrHttpChooser 实现之后完成,因为在这一点上它可能只需要知道客户端是否支持 SPDY
241+
242+
为了说明这一点,让我们总结一下,看看不同 ChannelPipeline 状态期间与客户连接的生命周期。图12.2显示了在 Channel 初始化后的 ChannelPipeline。
243+
244+
![](../images/Figure 12.2 ChannelPipeline after connection.jpg)
245+
246+
Figure 12.2 ChannelPipeline after connection
247+
248+
现在,这取决于客户端是否支持 SPDY,管道将修改DefaultSpdyOrHttpChooser 来处理协议。之后并不需要添加所需的 ChannelHandler 到 ChannelPipeline,所以删除本身。这个逻辑是由抽象 SpdyOrHttpChooser 类封装,DefaultSpdyOrHttpChooser 父类。
249+
250+
图12.3显示了支持 SPDY 的 ChannelPipeline 用于连接客户端的配置。
251+
252+
![](../images/Figure 12.3 ChannelPipeline if SPDY is supported.jpg)
253+
254+
Figure 12.3 ChannelPipeline if SPDY is supported
255+
256+
每个 ChannelHandler 负责的一小部分工作,这个就是对基于 Netty 构造的应用程序最完美的诠释。每个 ChannelHandler 的职责如表12.3所示。
257+
258+
Table 12.3 Responsibilities of the ChannelHandlers when SPDY is used
259+
260+
名称 | 职责
261+
----|----
262+
SslHandler | 加解密两端交换的数据
263+
SpdyFrameDecoder | 从接收到的 SPDY 帧中解码字节
264+
SpdyFrameEncoder | 编码 SPDY 帧到字节
265+
SpdySessionHandler | 处理 SPDY session
266+
SpdyHttpEncoder | 编码 HTTP 消息到 SPDY 帧
267+
SpdyHttpDecoder | 解码 SDPY 帧到 HTTP 消息
268+
SpdyHttpResponseStreamIdHandler | 处理基于 SPDY ID 请求和响应之间的映射关系
269+
SpdyRequestHandler | 处理 FullHttpRequest, 用于从 SPDY 帧中解码,因此允许 SPDY 透明传输使用
270+
271+
当协议是 HTTP(s) 时,ChannelPipeline 看起来相当不同,如图13.4所示。
272+
273+
![](../images/Figure 12.3 ChannelPipeline if SPDY is not supported.jpg)
274+
275+
Figure 12.3 ChannelPipeline if SPDY is not supported
276+
277+
和之前一样,每个 ChannelHandler 都有职责,定义在表12.4
278+
279+
Table 12.4 Responsibilities of the ChannelHandlers when HTTP is used
280+
281+
名称 | 职责
282+
----|----
283+
SslHandler | 加解密两端交换的数据
284+
HttpRequestDecoder | 从接收到的 HTTP 请求中解码字节
285+
HttpResponseEncoder | 编码 HTTP 响应到字节
286+
HttpObjectAggregator 处理 SPDY session
287+
HttpRequestHandler | 解码时处理 FullHttpRequest
288+
289+
### 所有东西组合在一起
290+
291+
所有的 ChannelHandler 实现已经准备好,现在组合成一个 SpdyServer
292+
293+
Listing 12.6 SpdyServer implementation
294+
295+
public class SpdyServer {
296+
297+
private final NioEventLoopGroup group = new NioEventLoopGroup(); //1
298+
private final SslContext context;
299+
private Channel channel;
300+
301+
public SpdyServer(SslContext context) { //2
302+
this.context = context;
303+
}
304+
305+
public ChannelFuture start(InetSocketAddress address) {
306+
ServerBootstrap bootstrap = new ServerBootstrap(); //3
307+
bootstrap.group(group)
308+
.channel(NioServerSocketChannel.class)
309+
.childHandler(new SpdyChannelInitializer(context)); //4
310+
ChannelFuture future = bootstrap.bind(address); //5
311+
future.syncUninterruptibly();
312+
channel = future.channel();
313+
return future;
314+
}
315+
316+
public void destroy() { //6
317+
if (channel != null) {
318+
channel.close();
319+
}
320+
group.shutdownGracefully();
321+
}
322+
323+
public static void main(String[] args) throws Exception {
324+
if (args.length != 1) {
325+
System.err.println("Please give port as argument");
326+
System.exit(1);
327+
}
328+
int port = Integer.parseInt(args[0]);
329+
330+
SelfSignedCertificate cert = new SelfSignedCertificate();
331+
SslContext context = SslContext.newServerContext(cert.certificate(), cert.privateKey()); //7
332+
final SpdyServer endpoint = new SpdyServer(context);
333+
ChannelFuture future = endpoint.start(new InetSocketAddress(port));
334+
335+
Runtime.getRuntime().addShutdownHook(new Thread() {
336+
@Override
337+
public void run() {
338+
endpoint.destroy();
339+
}
340+
});
341+
future.channel().closeFuture().syncUninterruptibly();
342+
}
343+
}
344+
345+
1. 构建新的 NioEventLoopGroup 用于处理 I/O
346+
2. 传递 SSLContext 用于加密
347+
3. 新建 ServerBootstrap 用于配置服务器
348+
4. 配置 ServerBootstrap
349+
5. 绑定服务器用于接收指定地址的连接
350+
6. 销毁服务器,用于关闭管道和 NioEventLoopGroup
351+
7. 从 BogusSslContextFactory 获取 SSLContext 。这是一个虚拟实现进行测试。真正的实现将为 SslContext 配置适当的密钥存储库。
9.14 KB
Loading[フレーム]
13.2 KB
Loading[フレーム]
18.5 KB
Loading[フレーム]

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /