Netty in Action (二十三) 第十二章节 WebSocket

第三部分:网络协议

WebSocket是一个先进的网络协议,被开发用来用来提高网络的性能和web应用的响应率,我们将介绍Netty对WebSocket这两个特性的支持,同时我们也会举一个简单的实例来说明讲解这两个WebSocket的特性

在第十二章节中,你将学会如何使用WebSocket实现数据双向传输的功能,我们会写一个聊天室的方式讲解这个数据双向传输的问题,我们这个聊天室的实例是这样的:多个浏览器客户端可是实时的相互通信,你也会学会如何将普通的HTTP协议切换升级成WebSocket协议,当然我们需要提前检测客户端是否支持WebSocket

我们也会在第三部分的最后介绍Netty对User Dategram Protocol(UDP)协议的支持,我们将会构建一个广播机制的服务器,并且会监控客户端的状态,以致客户端可以适用更多的实际的使用

第十二章:WebSocket

本章内容包括:

1)实时网络的概念

2)WebSocket协议

3)使用Netty构建基于WebSocket的聊天室服务端

如果你比较了解近期的Web应用的发展的话,你肯定会接触过“实时web”这个概念,如果你有实时系统有过实战的经验的话,你可能会在质疑“实时web”这个意味着什么

所以我们一开始就需要澄清这个概念,这并不是我们称之为“全实时品质服务”,我们可以称之为“近实时服务”,在这种场景下,后台的计算结果必须在指定的时间内给以传播,这个指定的时间比较给以保证,但是请求响应的这种HTTP协议设计并不是适合这种场景,如果运用到这种场景会有很多问题,因为你不知道什么时候去请求,截止到目前为止,事实证明目前还没有任何方案被设计出来,还没有任何方案被认为是令人满意的

尽管现在还有很多学术的讨论关于“timed web services”这个词汇的定义,现在被普遍接受的概念目前为止还没有出现,所以目前为止,我们只能从维基百科中接受一个并不是权威的对real-time web的定义:

一个近实时的web是需要网络web系统使用某种技术或者某种策略使使用者能够最快速度的获取信息,而不是需要使用者或者客户端使用他们的软件去主动调用或者检测某个数据源是否发生了变更

从技术上简单地陈述一下,也许一个成熟的实时web也许还没有真正的到来,但是在这个理念会加速大家对这个技术的期望,有了这种技术你可以几乎瞬发地获取到信息,这个章节我们讨论的WebSocket协议是近实时技术研究方向上前进的很扎实的一步

12.1 Introducing WebSocket

WebSocket协议是被设计来用来解决web应用中数据双向传输的一个实际的解决方案,这种协议可以是服务器和客户端在任何事件可以传输信息,因此,需要它们可以异步地处理信息

Netty对WebSocket的支持包括了对WebSocket的很多主要实现,所以你可以直接在你的项目中直接采用Netty提供的WebSocket服务是很直接方便的,与Netty设计的理念一样,你可以充分地使用WebSocket协议在不需要关心它内部的实现细节上,我们将通过使用WebSocket协议创建一个实时的web版的聊天系统

12.2 Our example WebSocket application

我们的示例应用将通过使用WebSocket协议来实现一个基于浏览器的聊天应用来说明实时通讯的功能,这种实例很类似于你在FaceBook上遇到的那种文本消息的交互,我们也会将我们的示例支持多个用户可以同时使用,进行相互通信

图12.1说明了我们示例的主要逻辑

1)客户端发送信息

2)发送的信息广播到所有其他链接的客户端中

这就是一个聊天室如何工作的基本逻辑:每个人可以其他的每个人进行交谈,在我们的示例中我们只会实现我们的服务端的代码,客户端则是通过浏览器的一些功能去简单实现的,在接下来的几页内容里,你会看见Netty的WebSocket是如何简单地构建这个示例的

12.3 Adding WebSocket support

升级握手机制被用来将标准的HTTP协议或者HTTPS协议切换成WebSocket协议,当然一个应用会以HTTP/S开始在需要升级的场景下升级为WebSocket应用,这种升级可以是由某个具体的URL指定触发的

我们的应用就会使用这样的升级机制,如果一个URL请求是以/ws为结尾的,我们将协议升级成WebSocket协议,否则我们默认使用最基本的HTTP/S协议,当连接成功升级之后,所有的数据将使用WebSocket协议进行传播,图12.2说明了服务器的逻辑,服务器使用的是Netty,具体是通过一系列的ChannelHandler实现的,在下一个小节中,我们将具体来描述这些组件,我们会解释这些处理HTTP和WebSocket协议的技术

12.3.1 Handling HTTP requests

首先我们将会实现用来处理HTTP请求的组件,这个组件服务于网页端,用来提供聊天室的入口,并且用来展示由每个连接客户端发送信息的展示,代码清单12.1展示了HttpRequestHandler的具体实现,这个类继承于SimpleChannelInboundHandler用来处理FullHttpRequest信息,请注意代码实现中,方法channelRead0的实现是如何处理URI中以/ws为结尾的请求的

如果一个URI请求中有“/ws”的时候,HttpRequestHandler将会在FullHttpRequest上调用retain方法,再通过fireChannelRead(msg)方法使其转向到下一个ChannelInboundHandler中,调用retain是有必要的,因为在channelRead方法完成之后,它将会对FullHttpRequest调用release方法来释放资源

如果一个客户端发送一个HTTP1.1的消息头,期待一个"100-continue",那么HttpRequestHandler将会发送一个100-continue的响应,在所有的消息头被设置后,HttpRequestHandler将会写一个HttpResponse返回给客户端,返回的并不是一个完整的FullHttpResponse,因为它只是响应的第一个部分,所以在这里并没有调用writeAndFlush方法,这个方法将会在结尾调用

如果加密和压缩都不需要的情况下,那么我们可以在DefaultFileRegion中存储index.html的内容,这样可以获取最大的效率,这样可以利用零拷贝技术来获取最高的传输效率,因为这个理由,你可以了解在一个ChannelPipeline中是否有SslHandler,如果有,你就有可选方案可以使用ChunkedNioFile

HttpRequestHandler写一个LastHttpContent来标记一个响应的结束,如果不需要keepalive,那么HttpRequestHandler将会在最后写入结束的时候的ChannelFuture增加一个ChannelFutureListener来关闭连接,在这里你就可以调用writeAndFlush方法来将值钱所有写入的信息刷入

目前为止,这块代码代表了聊天室的第一个模块,它将管理纯净的HTTP请求和响应,下一个小节,我们将处理WebSocket协议的帧数据,这个数据将承载着真实的聊天信息

12.3.2 Handling WebSocket frames

RFC的WebSocket协议由IETF发布的,规范了六种类型的帧数据,Netty为每一种帧数据提供了一个POJO的实现,表12.1列出了这些帧数据的类型并且描述他们的使用说明

我们的聊天室将使用如下的数据帧类型

1)CloseWebSocketFrame

2)PingWebSocketFrame

3)PongWebSocketFrame

4)TextWebSocketFrame

事实上TextWebSocketFrame类型的数据是我们真正需要处理的,为了符合RFC的WebSocket,Netty提供了WebSocketServerProtocolHandler来管理其他类型的帧数据

下面的代码清单展示用来处理TextWebSocketFrame的ChannelInboundHandler,这个也可以用来追踪在ChannelGroup中的存活的WebSocket连接

TextWebSocketFrameHandler只负责很小一块的功能,当WebSocket与新的客户端成功握手之后,它将会通知所有的连接着的所有客户端,通过将其写入ChannelGroup的所有Channel中,然后它将新增的Channel写入ChannelGroup中

如果一个TextWebSocketFrame被接收,那么它将对TextWebSocketFrame对象调用retain方法,然后使用writeAndFlush方法将其传输到ChannelGroup中以致于所有的连接的WebSocket的Channel都能接收到这个讯息

在之前,调用retain方法是有必要的,是因为当channelRead0的方法返回的时候TextWebSocketFrame这个对象的计数引用会递减一,因为所有的操作都是异步的,writeAndFlush可能会在有一定的延迟的时间内完成,所以我们不允许获取一个不合法的对象引用,所以调用retain方法

因为Netty内部已经给我们的WebSocket的实现完成了大部分的工作,唯一剩下来的事情就是初始化好ChannelPipeline,因为每一个新的Channel都在这创建的,因为这个原因,我们需要一个ChannelInitializer

12.3.3 Initializing the ChannelPipeline

因为我们之前已经学习过,在ChannelPipeline中安装ChannelHandler时,你只需要继承ChannelInitializer类,然后实现initChannel方法,下面的代码清单展示了ChatServerInitializer的具体实际代码

initChannel方法的调用可以设置ChannelPipeline中注册的Channel,通过这种方法可以安装所需的所有ChannelHandler,在表12.2给出了部分摘要,每一个都描述了他们自己负责的功能

Netty的WebSocketServerProtocolHandler处理所有已经授权的WebSocket帧类型的数据,并且同时升级握手,如果握手成功,指定的一些ChannelHandler需要增加到管道中,如果没有需要,那么这些handler将不会再从管道中移除

在协议升级之前管道的状态如图12.3所示,这张图代表了又ChatServerInitializer初始化之后的管道的状态

当协议升级之后,WebSocketServerProtocolHandler将会以WebSocketFrameDecoder取代HttpRequestDecoder,以WebSocketFrameEncoder取代HttpResponseEncoder

,为了最大化性能,它会在这个时候移除任何不需要的多余的Handler,这些Handler可能WebSocket使用不到,这些Handler包括如12.3所示的HttpObjectAggregator和HttpRequestHandler

图12.4展示了当操作升级完成后管道的状态,注意目前为止Netty支持四种类型版本的WebSocket,每一个版本都有他们自己的实现,选择正确的WebSocketFrameDecoder和WebSocketFrameEncoder这个行为是自动完成的,这取决于你客户端也就是浏览器支持哪一种版本的webSocket

12.3.4 Bootstrapping

这个聊天室的最后一个模块就是启动服务器初始化所有的ChatServerInitializer,这些动作将被ChatServer处理,如下面展示的一样

应用的所有代码已经完成了,现在我们开始测试

12.4
Testing the application

第十二章节的所有代码示例已经全部给出了,现在你需要构建运行测试用例,我们可以使用如下的Maven命令来构建和启动项目

这个项目的pom.xml配置了在端口9999来启动项目,如果你想要使用其他的端口,你可以不需要编辑改变量,你可以在命令中重新覆盖该变量

下面是控制台打印的构建和启动的日记

在你的浏览器中输入http://localhost:9999来进入你的应用,图12.5展示了Chrome浏览器的UI

图12.5展示了两个链接的客户端,第一个连接是使用浏览器页面头部提供的输入接口,第二个连接是通过浏览器的底部的控制台连接的,你会发现无论从这两个客户端的发送的信息,发送的信息都能够在其他的客户端中正常的展示

这就是一个完整的示例,这个示例很好地展示了在一个浏览器中WebSocket如何构建一个实时通讯的

12.4.1 What about encryption?

在真实的生产环境中,你将很快被要求将加密器加入到你的应用中,对于Netty应用来说,这是小事一桩,你只需要将SslHandler加入到ChannelPipeline中去然后配置一下就可以了,下面的代码清单展示了我们是如何实现这个功能的,我们只需要创建一个SecureChatServerInitializer,使其继承与ChatServerInitializer就可以了

最后一步就是让ChatServer采用我们刚刚创建的SecureChatServerInitializer这样就可以使SslHandler加入到管道中去,我们使用SecureChatServer实现了这个效果

这样就可以使整个通讯都支持SSL/TLS的加密了,与之前一样,我们依旧使用Maven去构建一下

现在你又可以在http://localhost:9999看到SecureChatServer了

12.5 Summary

在这个章节中,我们使用了Netty实现的WebSocket写了一个网页版的实时数据系统,我们讲解了WebSocket支持的数据类型,也讨论了我们遇到的一些限制,尽管并不是每一个场景都可以使用WebSocket的,但是有一点是毫无疑问的,对于web开发来说,WebSocket技术是这个方面的一个很重要的一大突破

时间: 2024-10-08 14:57:45

Netty in Action (二十三) 第十二章节 WebSocket的相关文章

Netty in Action (十三) 第五章节 第二部分 ByteBuf字节层面的操作

5.3 Byte-level operations ByteBuf除了提供基本对数据读写操作之外,它还提供了很多其他的方法,在接下来的这个小节中,我们将讨论这些方法中比较重要的来分析讲解一下 5.3.1 Random access indexing 与正常的java的字节数组一样,ByteBuf的索引下标也是从0开始的,第一个索引下表是0,最后一个字节索引总是它的容量-1,下面的代码清单向你展示了ByteBuf封装了它的存储机制,可以使我们很方便地去迭代ByteBuf中的内容 注意到如果想获取B

#Java学习之路——基础阶段二(第十二篇)

我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言:此随笔主要是Java基础中的基础,相信大家对这方面肯定有着自己的理解和认识,具体详解可以参照万能的baidu,有的我就一笔带过,希望在我的学习之路上能够有大牛进行指导,也有更多的小伙伴共勉. 1.Web阶段回顾 1.软件架构 C/S  和 B/S  他们的优缺点 2.资源分类 静态资源和动态资源.两

Netty in Action (七) 第三章节 Netty组件和设计

这个章节包括: 1)Netty的架构设计和技术点 2)Channel,EventLoop和ChannelFuture 3)ChannelHandler 和 ChannelPipeline 4)Bootstrap 在第一章节中,我们讲述了java在高性能的网络编程的发展历史和对网络方面的技术基础的积累,这给对Netty的核心组件和构建模块分析提供了一个很好的氛围 在第二章节中,我们扩大了我们的讨论范围,我们构建了我们第一个基于Netty的应用,通过构建简单的服务器端和客户端让我们了解了如何启动Ne

Netty in Action (十七) 第七章节 EventLoop和线程模型

本章节包括: 1)线程模型总览 2)Event Loop概念和具体实现 3)任务调度 4)实现细节 简单地陈述一下,对于一个操作系统,编程语言,框架,或者应用来说,线程模型对其都是至关重要的一部分,在什么时间如何创建一个线程都会对你的代码执行有很重要的影响,所以对于开发人员而言,懂得在各种线程模型里面权衡利弊就是一个很重要的事情,是直接使用线程模型本身还是通过一些框架或者语言提供的线程框架对于开发者而言都是需要选择的 在这个章节,我们将会详细地讲解Netty的线程模型,这个模型是很强大的,且易于

Mina、Netty、Twisted一起学(十):线程模型

要想开发一个高性能的TCPserver,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,假设再搭配上高效率的代码.才干实现一个高大上的server. 可是假设不了解它们的线程模型.就非常难写出高性能的代码.框架本身效率再高.程序写的太差,那么server总体的性能也不会太高.就像一个电脑,CPU再好.内存小硬盘慢散热差,总体的性能也不会太高. 玩过Android开发的同学会知道,在Android应用中有一个非常重要线程:UI线程(即主线程). UI

第十二、十三周新总结

第十二.十三周总结 ——————————————王林 学科 WEB 数据结构 计算机网络基础 课外读物 进度 第十章.第十一章 第六章后半部分,第七章前半部分 项目6.项目7 <黑客攻防从新手到高手> <Flash MX> 主要内容 第十二周.第十三周主要学习了CSS3的知识.包括CSS3字体与文本的相关属性.设计立体文本.美化背景与边框.设置背景.边框设置.以及综合实例. 两周内.,重点学习了二叉树等. 十二周内,学习了无线局域网的基础知识.无线网络的硬件设备ji组网模式及认证I

阅读《构建之法》十一、十二、十三章之感

第十一章 问题:为了避免误解,我们是不是可以把我们理解的告诉用户,并且最好是图像的形势或是其他方式展示给用户? 第十二章 问题:为了让用户满意,是否可以在用户的原来基础上创新,体现出一些人文关怀,请问这是一些好的想法吗?还是这是程序员的顾忌? 第十三章 问题:(220)文中提到用户需要帮助,但是用户没有那么蠢.是一个人非常典型的例子,但是这个例子问题太过突出.有时候就算我们记住了用户的选择,考虑了用户的感受,但是还是难免把握住那住个度,那么我们如何准确的把握住那个度.

Netty in Action (二十一) 第十一章节 第一部分 Netty提供的一些原生Handler和codecs

本章内容包括(分2次翻译): 1)利用SSL/TLS构建安全的Netty应用 2)构建HTTP/HTTPS的应用 3)处理闲置的连接和超时 4)空格符切分协议和长度切分的协议的解码 5)写入大数据 Netty为各式各样的协议提供了很多译码器和处理器的类,这些类你可以做到拿来即用,可以使你在有些比较麻烦的事件上不用花费不必要的时间和精力,在这个章节我们将会把这些工具介绍给你,且一一分析他们的作用,这些工具包括:支持SSL/TLS和Websocket的工具,也有比HTTP天然的数据压缩更高性能的数据

网络操作系统第十二、十三章习题

第十二章习题 1.简述FTP的连接模式. 答:FTP的连接模式有RORT和PASV两种,其中RORT是主动模式,PASV是被动模式,这里说的主动和被动都是相对与服务器而言的.如果是主动模式,数据端口为20,如果是被动模式,则由服务器端和客户端协商而定. 2.简述FTP的传输模式. 答:FTP的传输模式包括ASCII传输模式和二进制模式.ASCII传输模式适合用于文本传输,二进制传输模式适合用于非文本传输. 3.如何在Windows系统中配置FTP服务器? 答:在安装服务器时,在"FTP站点&qu