<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 實現 SPDY 使用 TLS 的擴展稱為 Next Protocol Negotiation (NPN)。在Java 中,我們有兩種不同的方式選擇的基于 NPN 的協議: - 使用 ssl_npn,NPN 的開源 SSL 提供者。 - 使用通過 Jetty 的 NPN 擴展庫。 在這個例子中使用 Jetty 庫。如果你想使用 ssl_npn,請參閱[https://github.com/benmmurphy/ssl_npn](https://github.com/benmmurphy/ssl_npn)項目文檔 *Jetty NPN 庫* *Jetty NPN 庫是一個外部的庫,而不是 Netty 的本身的一部分。它用于處理 Next Protocol Negotiation, 這是用于檢測客戶端是否支持 SPDY。* ### 集成 Next Protocol Negotiation Jetty 庫提供了一個接口稱為 ServerProvider,確定所使用的協議和選擇哪個鉤子。這個的實現可能取決于不同版本的 HTTP 和 SPDY 版本的支持。下面的清單顯示了將用于我們的示例應用程序的實現。 Listing 12.1 Implementation of ServerProvider ~~~ public class DefaultServerProvider implements NextProtoNego.ServerProvider { private static final List<String> PROTOCOLS = Collections.unmodifiableList(Arrays.asList("spdy/2", "spdy/3", "http/1.1")); //1 private String protocol; @Override public void unsupported() { protocol = "http/1.1"; //2 } @Override public List<String> protocols() { return PROTOCOLS; //3 } @Override public void protocolSelected(String protocol) { this.protocol = protocol; //4 } public String getSelectedProtocol() { return protocol; //5 } } ~~~ 1. 定義所有的 ServerProvider 實現的協議 1. 設置如果 SPDY 協議失敗了就轉到 http/1.1 1. 返回支持的協議的列表 1. 設置選擇的協議 1. 返回選擇的協議 在 ServerProvider 的實現,我們支持下面的3種協議: - SPDY 2 - SPDY 3 - HTTP 1.1 如果客戶端不支持 SPDY ,則默認使用 HTTP 1.1 #### 實現各種 ChannelHandler 第一個 ChannelInboundHandler 是用于不支持 SPDY 的情況下處理客戶端 HTTP 請求,如果不支持 SPDY 就回滾使用默認的 HTTP 協議。 清單12.2顯示了HTTP流量的處理程序。 Listing 12.2 Implementation that handles HTTP ~~~ @ChannelHandler.Sharable public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> { @Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { //1 if (HttpHeaders.is100ContinueExpected(request)) { send100Continue(ctx); //2 } FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK); //3 response.content().writeBytes(getContent().getBytes(CharsetUtil.UTF_8)); //4 response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); //5 boolean keepAlive = HttpHeaders.isKeepAlive(request); if (keepAlive) { //6 response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes()); response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } ChannelFuture future = ctx.writeAndFlush(response); //7 if (!keepAlive) { future.addListener (ChannelFutureListener.CLOSE); //8 } } protected String getContent() { //9 return "This content is transmitted via HTTP\r\n"; } private static void send100Continue(ChannelHandlerContext ctx) { //10 FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE); ctx.writeAndFlush(response); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { //11 cause.printStackTrace(); ctx.close(); } } ~~~ 1. 重寫 channelRead0() ,可以被所有的接收到的 FullHttpRequest 調用 1. 檢查如果接下來的響應是預期的,就寫入 1. 新建 FullHttpResponse,用于對請求的響應 1. 生成響應的內容,將它寫入 payload 1. 設置頭文件,這樣客戶端就能知道如何與 響應的 payload 交互 1. 檢查請求設置是否啟用了 keepalive;如果是這樣,將標題設置為符合HTTP RFC 1. 寫響應給客戶端,并獲取到 Future 的引用,用于寫完成時,獲取到通知 1. 如果響應不是 keepalive,在寫完成時關閉連接 1. 返回內容作為響應的 payload 1. Helper 方法生成了100 持續的響應,并寫回給客戶端 1. 若執行階段拋出異常,則關閉管道 這就是 Netty 處理標準的 HTTP 。你可能需要分別處理特定 URI ,應對不同的狀態代碼,這取決于資源存在與否,但基本的概念將是相同的。 我們的下一個任務將會提供一個組件來支持 SPDY 作為首選協議。Netty 提供了簡單的處理 SPDY 方法。這些將使您能夠重用FullHttpRequest 和 FullHttpResponse 消息,通過 SPDY 透明地接收和發送他們。 HttpRequestHandler 雖然是我們可以重用代碼,我們將改變我們的內容寫回客戶端只是強調協議變化;通常您會返回相同的內容。下面的清單展示了實現,它擴展了先前的 HttpRequestHandler。 Listing 12.3 Implementation that handles SPDY ~~~ @ChannelHandler.Sharable public class SpdyRequestHandler extends HttpRequestHandler { //1 @Override protected String getContent() { return "This content is transmitted via SPDY\r\n"; //2 } } ~~~ 1. 繼承 HttpRequestHandler 這樣就能共享相同的邏輯 1. 生產內容寫到 payload。這個重寫了 HttpRequestHandler 的getContent() 的實現 SpdyRequestHandler 繼承自 HttpRequestHandler,但區別是:寫入的內容的 payload 狀態的響應是在 SPDY 寫的。 我們可以實現兩個處理程序邏輯,將選擇一個相匹配的協議。然而添加以前寫過的處理程序到 ChannelPipeline 是不夠的;正確的編解碼器還需要補充。它的責任是檢測傳輸字節數,然后使用 FullHttpResponse 和 FullHttpRequest 的抽象進行工作。 Netty 的附帶一個基類,完全能做這個。所有您需要做的是實現邏輯選擇協議和選擇適當的處理程序。 清單12.4顯示了實現,它使用 Netty 的提供的抽象基類。 ~~~ public class DefaultSpdyOrHttpChooser extends SpdyOrHttpChooser { public DefaultSpdyOrHttpChooser(int maxSpdyContentLength, int maxHttpContentLength) { super(maxSpdyContentLength, maxHttpContentLength); } @Override protected SelectedProtocol getProtocol(SSLEngine engine) { DefaultServerProvider provider = (DefaultServerProvider) NextProtoNego.get(engine); //1 String protocol = provider.getSelectedProtocol(); if (protocol == null) { return SelectedProtocol.UNKNOWN; //2 } switch (protocol) { case "spdy/2": return SelectedProtocol.SPDY_2; //3 case "spdy/3.1": return SelectedProtocol.SPDY_3_1; //4 case "http/1.1": return SelectedProtocol.HTTP_1_1; //5 default: return SelectedProtocol.UNKNOWN; //6 } } @Override protected ChannelInboundHandler createHttpRequestHandlerForHttp() { return new HttpRequestHandler(); //7 } @Override protected ChannelInboundHandler createHttpRequestHandlerForSpdy() { return new SpdyRequestHandler(); //8 } } ~~~ 1. 使用 NextProtoNego 用于獲取 DefaultServerProvider 的引用, 用于 SSLEngine 1. 協議不能被檢測到。一旦字節已經準備好讀,檢測過程將重新開始。 1. SPDY 2 被檢測到 1. SPDY 3 被檢測到 1. HTTP 1.1 被檢測到 1. 未知協議被檢測到 1. 將會被調用給 FullHttpRequest 消息添加處理器。該方法只會在不支持 SPDY 時調用,那么將會使用 HTTPS 1. 將會被調用給 FullHttpRequest 消息添加處理器。該方法在支持 SPDY 時調用 該實現要注意檢測正確的協議并設置 ChannelPipeline 。它可以處理SPDY 版本 2、3 和 HTTP 1.1,但可以很容易地修改 SPDY 支持額外的版本。 ### 設置 ChannelPipeline 通過實現 ChannelInitializer 將所有的處理器連接到一起。正如你所了解的那樣,這將設置 ChannelPipeline 并添加所有需要的ChannelHandler 的。 SPDY 需要兩個 ChannelHandler: - SslHandler,用于檢測 SPDY 是否通過 TLS 擴展 - DefaultSpdyOrHttpChooser,用于當協議被檢測到時,添加正確的 ChannelHandler 到 ChannelPipeline 除了添加 ChannelHandler 到 ChannelPipeline, ChannelInitializer 還有另一個責任;即,分配之前創建的 DefaultServerProvider 通過 SslHandler 到 SslEngine 。這將通過Jetty NPN 類庫的 NextProtoNego helper 類實現 Listing 12.5 Implementation that handles SPDY ~~~ public class SpdyChannelInitializer extends ChannelInitializer<SocketChannel> { //1 private final SslContext context; public SpdyChannelInitializer(SslContext context) //2 { this.context = context; } @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); SSLEngine engine = context.newEngine(ch.alloc()); //3 engine.setUseClientMode(false); //4 NextProtoNego.put(engine, new DefaultServerProvider()); //5 NextProtoNego.debug = true; pipeline.addLast("sslHandler", new SslHandler(engine)); //6 pipeline.addLast("chooser", new DefaultSpdyOrHttpChooser(1024 * 1024, 1024 * 1024)); } } ~~~ 1. 繼承 ChannelInitializer 是一個簡單的開始 1. 傳遞 SSLContext 用于創建 SSLEngine 1. 新建 SSLEngine,用于新的管道和連接 1. 配置 SSLEngine 用于非客戶端使用 1. 通過 NextProtoNego helper 類綁定 DefaultServerProvider 到 SSLEngine 1. 添加 SslHandler 到 ChannelPipeline 這將會在協議檢測到時保存在 ChannelPipeline 1. 添加 DefaultSpyOrHttpChooser 到 ChannelPipeline 。這個實現將會監測協議。添加正確的 ChannelHandler 到 ChannelPipeline,并且移除自身 實際的 ChannelPipeline 設置將會在 DefaultSpdyOrHttpChooser 實現之后完成,因為在這一點上它可能只需要知道客戶端是否支持 SPDY 為了說明這一點,讓我們總結一下,看看不同 ChannelPipeline 狀態期間與客戶連接的生命周期。圖12.2顯示了在 Channel 初始化后的 ChannelPipeline。 ![](https://box.kancloud.cn/2015-08-18_55d31292ae704.jpg) Figure 12.2 ChannelPipeline after connection 現在,這取決于客戶端是否支持 SPDY,管道將修改DefaultSpdyOrHttpChooser 來處理協議。之后并不需要添加所需的 ChannelHandler 到 ChannelPipeline,所以刪除本身。這個邏輯是由抽象 SpdyOrHttpChooser 類封裝,DefaultSpdyOrHttpChooser 父類。 圖12.3顯示了支持 SPDY 的 ChannelPipeline 用于連接客戶端的配置。 ![](https://box.kancloud.cn/2015-08-18_55d31292b6aa7.jpg) Figure 12.3 ChannelPipeline if SPDY is supported 每個 ChannelHandler 負責的一小部分工作,這個就是對基于 Netty 構造的應用程序最完美的詮釋。每個 ChannelHandler 的職責如表12.3所示。 Table 12.3 Responsibilities of the ChannelHandlers when SPDY is used | 名稱 | 職責 | |-----|-----| | SslHandler | 加解密兩端交換的數據 | | SpdyFrameDecoder | 從接收到的 SPDY 幀中解碼字節 | | SpdyFrameEncoder | 編碼 SPDY 幀到字節 | | SpdySessionHandler | 處理 SPDY session | | SpdyHttpEncoder | 編碼 HTTP 消息到 SPDY 幀 | | SpdyHttpDecoder | 解碼 SDPY 幀到 HTTP 消息 | | SpdyHttpResponseStreamIdHandler | 處理基于 SPDY ID 請求和響應之間的映射關系 | | SpdyRequestHandler | 處理 FullHttpRequest, 用于從 SPDY 幀中解碼,因此允許 SPDY 透明傳輸使用 | 當協議是 HTTP(s) 時,ChannelPipeline 看起來相當不同,如圖13.4所示。 ![](https://box.kancloud.cn/2015-08-18_55d31292bfbe0.jpg) Figure 12.3 ChannelPipeline if SPDY is not supported 和之前一樣,每個 ChannelHandler 都有職責,定義在表12.4 Table 12.4 Responsibilities of the ChannelHandlers when HTTP is used | 名稱 | 職責 | |-----|-----| | SslHandler | 加解密兩端交換的數據 | | HttpRequestDecoder | 從接收到的 HTTP 請求中解碼字節 | | HttpResponseEncoder | 編碼 HTTP 響應到字節 | HttpObjectAggregator 處理 SPDY sessionHttpRequestHandler | 解碼時處理 FullHttpRequest ### 所有東西組合在一起 所有的 ChannelHandler 實現已經準備好,現在組合成一個 SpdyServer Listing 12.6 SpdyServer implementation ~~~ public class SpdyServer { private final NioEventLoopGroup group = new NioEventLoopGroup(); //1 private final SslContext context; private Channel channel; public SpdyServer(SslContext context) { //2 this.context = context; } public ChannelFuture start(InetSocketAddress address) { ServerBootstrap bootstrap = new ServerBootstrap(); //3 bootstrap.group(group) .channel(NioServerSocketChannel.class) .childHandler(new SpdyChannelInitializer(context)); //4 ChannelFuture future = bootstrap.bind(address); //5 future.syncUninterruptibly(); channel = future.channel(); return future; } public void destroy() { //6 if (channel != null) { channel.close(); } group.shutdownGracefully(); } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Please give port as argument"); System.exit(1); } int port = Integer.parseInt(args[0]); SelfSignedCertificate cert = new SelfSignedCertificate(); SslContext context = SslContext.newServerContext(cert.certificate(), cert.privateKey()); //7 final SpdyServer endpoint = new SpdyServer(context); ChannelFuture future = endpoint.start(new InetSocketAddress(port)); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { endpoint.destroy(); } }); future.channel().closeFuture().syncUninterruptibly(); } } ~~~ 1. 構建新的 NioEventLoopGroup 用于處理 I/O 1. 傳遞 SSLContext 用于加密 1. 新建 ServerBootstrap 用于配置服務器 1. 配置 ServerBootstrap 1. 綁定服務器用于接收指定地址的連接 1. 銷毀服務器,用于關閉管道和 NioEventLoopGroup 1. 從 BogusSslContextFactory 獲取 SSLContext 。這是一個虛擬實現進行測試。真正的實現將為 SslContext 配置適當的密鑰存儲庫。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看