基于HTML5 WebSocket,JavaEE 7在线聊天系统
程序员文章站
2022-03-17 12:55:20
当今的Web应用在我们的个人生活与商业应用中的各个方面已经表现出愈发重要的作用。这些应用包括社交媒体网络、在线购
物、商业应用,乃至家用电器的配置程序。虽然它的增长势头依然迅猛,...
当今的Web应用在我们的个人生活与商业应用中的各个方面已经表现出愈发重要的作用。这些应用包括社交媒体网络、在线购
物、商业应用,乃至家用电器的配置程序。虽然它的增长势头依然迅猛,但Web应用的用户体验与原生应用或桌面应用相比仍然相
形见绌,其主要原因是Web应用的设计依赖于单向的HTTP协议。而WebSocket将改变这一现状,它为浏览器与服务端的交互带来了
一种新的基础元素,为创建一种能够提供真正的交互性体验的Web应用提供了必要的基础。
早期的Web技术都是基于HTTP协议而发展起来的,而HTTP只是一个简单的基于请求 —— 响应操作的协议,所有的请求都是
由客户端发起的。这套框架原本足以满足用户的需求,但在如今开发者所设计的web应用中,由客户端发起通信这种方式有着很大
的制约。虽然人们提出了各种临时方案,但它们都是基于HTTP协议的,只是应用了轮询或长轮询技术(例如Comet)。Comet能够让负责处理请求的线程得到释放,以防止服务器资源耗尽。由于轮询这种机制并不可靠,因此在2007年时,有人提出了一种名为
WebSocket的全双工(full-duplex)类型的通信方式。这项提议用了整整4年的时间才成为一个标准。但是,尽管它已成为一种标
准,但它的使用率却相当有限。WebSocket是在TCP/IP协议之上创建的一种帧协议,客户端将通过向服务器发送一种特殊的HTTP
请求以启动WebSocket。在最初的握手过程之后,客户端与服务器就能够*地以异步方式互相进行帧的传送了。帧分为两种类
型:即控制帧与数据帧。最小的控制帧仅有2比特的大小,而在数据帧方面,客户端的数据帧最小为6比特,服务端的数据帧最小为2
比特。数据帧既可以是文本型,也可以是二进制的。文本帧都经过了UTF-8的编码。帧可以实现分块,因此一个大数据集可以分解
为多个帧。WebSocket不会为帧附加任何标识信息,因此不同类型的信息对应的帧不可混用。只有控制帧能够在处理一个大消息时
的一系列中间帧中出现。在这些基础的帧之上,还可以定义更复杂的协议。比方说,一个帧能够带有校验和或是它的序列号等相关
信息。
WebSocket的API
WebSocket并不限定于仅在某个特定的编程语言、系统或是操作系统中使用。多数主流的编程语言以及许多浏览器都已开始支
持WebSocket的编程。虽然在不同的平台与编程语言中存在着大量的标准,但本文仅关注JavaScript HTML5以及Java(J2EE)对
WebSocket的支持。在浏览器这方面有两种实现标准,其最新版本分别为Hixie-76和HyBi-17(不久之后发展为IETF RFC 6455)。
HyBi的实现相对更高级,并且得到了目前所有主流浏览器的支持。而在服务端方面,基于Java的实现则是目前最为流行的。早些时
候在Java上曾经出现过几种WebSocket的实现,它们之后已发展为JSR 356这种实现。JSR代表Java规范请求,对规范请求的说明
有帮于让之后的各种实现保持一致性,并且易于使用。JSR也让开发者不必依赖于某个特定的实现。JSR 356与servlet规范是相互分
离的,但它也允许开发者访问某些servlet对象。JSR 356的内容涵盖了WebSocket连接的客户端与服务端, 我们稍后的讨论将集中
于配合浏览器端的JavaScript所实现的服务端。JSR 356目前属于J2EE 7的一部分,所有流行的开源Java应用服务器都支持它,包
括Tomcat、Jetty、Glassfish以及TJWS等等。除此之外,在Java环境中还存在着大约20种各自独立的WebSocket服务端解决方案,
其中有些方案也支持JSR 356。由于WebSocket是J2EE 7的一部分,因而在由Oracle与IBM所推出的商业应用服务器上同样也得到
支持。
正如我之前所说,WebSocket是一种消息传递协议。它的API提供了各种在通信双方进行消息传递与接收的方法。这里并不存
在经典的订阅者与发布者的关系。消息只有两种类型,即文本型与二进制型。不过,在这些类型的消息处理函数中可以对消息进行
逻辑上的分离。在Java中能够以某种方式处理被分解为多个块的部分消息,JavaScript尚未支持这种程度的控制能力。如同之前所
说,WebSocket是一种非常泛用的协议,它可以在握手时指定所需的逻辑子协议。当不同的系统能够验证所连到的系统支持这种逻
辑子协议及扩展时,使用WebSocket进行系统集成就变得容易很多。WebSocket帧格式允许在它的基础上使用可协商的扩展,这与
意味着一般来说帧可能会提供更多的信息,并且可能会引入不同的帧类型。
WebSocket对于以下类型的应用程序的开发是一种非常自然的选择:
需要玩家之间实时协作的游戏
实时监控系统
需要用户进行协作的系统,例如聊天、共享文档的编辑等等。
其实,WebSocket在传统的Web应用中也能够展现其优势。大多数Web应用都是基于请求 - 响应这一范式进行设计的。虽然
AJAX能够实现异步操作,但在继续处理下一步操作之间,仍然必须等待响应返回。而由于WebSocket连接只需建立一次,从而避免
了为每次数据交换重建连接的过程,并且在后续的通信中也无需发送多余的HTTP头信息。这种优势在SSL类型的连接上体现得尤为
明显,因为最初的连接握手是一个开销很大的操作。浏览器端的WebSocket发送操作是完全异步的,而Java的服务端代码在发送消
息后无需进行等待。由于发送消息的这种*度,在应用中或许需要对某些操作进行手动记录,以保持应用状态的一致性。在使用
WebSocket时也能够模拟请求 - 响应这一范式,但如此一来,WebSocket作为一种真正的异步双向消息传递系统的优势也被大大消
减了。由于以上所描述的这些特性,因此应当鼓励开发者在某些场景中对应用程序的设计方式进行重新思考。
假设某一个应用程序包含了复杂的用户界面,其中某些区域的功能需要通过服务端的大量计算才能够生成对应的内容。传统的
基于AJAX的实现方式可以选择一种延迟调用的机制,通过某个内容请求调用以生成这一区域的内容。而在使用WebSocket的场合
下,服务端可以在浏览器做好准备的情况下直接发送内容,而无需对某个AJAX请求进行响应。AJAX请求这一方式的缺陷在于,由
于浏览器所发送的请求是串行的,因此服务端的处理过程无法针对请求的顺序进行相应的优化。而WebSocket为服务端提供了一个
自行决定最佳的内容生成方式的机会,因而能够提升Web应用的整体响应性。
要用效地利用WebSocket的功能,还需要仔细考虑几个额外的要点。由于在WebSocket中随时可能出现网络连接的丢失,使数
据无法正确地传递,因此对于一些至关重要的数据需要进行一些额外的手动记录操作。一般来说,所收到的每条消息都必须提供足
够的信息,以指示如何对其进行处理。但没有有效的手段能够了解信息的请求者是谁,是来自客户端的请求,还是说服务端想要更
新某些内容。在具体使用WebSocket的过程中,可能需要对Web应用的设计进行更深入的重新思考。此外,JavaScript代码的功能可
以迁移至服务端,打个比方,用户的输入可以立即发送给服务端进行处理,通过这种方式能够实现一些复杂的数据校验操作,而这
些校验功能或许是JavaScript所无法处理的。用户的输入还能够即时地保存在后台系统中,因此浏览器就无需将最终的数据传递给服
务器进行额外的数据校验,因为数据在保存在后台期间已经经过了校验。如果要使某个应用从富Web客户端转为一种轻量级的客户
端,就可以考虑以这种方式增加服务端代码的职责。
使用WebSocket时所需注意的要点
在Web应用开发时使用WebSocket也会面对一些特别的挑战,WebSocket的Session与HTTP的Session之间并无任何关联,虽
然也可将其用作类似的目标。在Session中可以附加某些通用的数据,因此所有的消息处理过程都可以依赖于Session中所维护的某
些状态和数据。WebSocket的Session也可以根据空闲(不活跃)时间间隔的配置产生超时情况,正如HTTP Session一样。不过有
些系统会自动地持续发送Ping这一控制消息,以防止出现超时。JSR 356建议将HTTP Session与WebSocket Session的超时进行同
步。一旦HTTP Session超时,在其范围内所创建的所有WebSocket连接也都必须关闭。但有些Web应用的设计不会产生任何HTTP
Session,而有些应用的Session超时不依赖于HTTP Session,而是由JavaScript所管理的,因此这种机制并不能够进行可靠的推广。
另一种需要注意的要点在于,某些浏览器会维护一个连接池,以重用连接的方式访问相同的网站,因此这种流程可以被串行
化。而如果浏览器为WebSocket连接也创建一个连接池,那么它会受到严重的制约。因为如果没有某种机制保持WebSocket连接的
关闭,这个连接就永远处于活跃状态,而其它任何创建新连接的尝试都会产生死锁。因此,最佳实践的推荐做法是只使用一个
WebSocket连接。浏览器无法对通过WebSocket进行传递的数据进行缓存,因此通过WebSocket传递可以在浏览器中缓存的资源。
物、商业应用,乃至家用电器的配置程序。虽然它的增长势头依然迅猛,但Web应用的用户体验与原生应用或桌面应用相比仍然相
形见绌,其主要原因是Web应用的设计依赖于单向的HTTP协议。而WebSocket将改变这一现状,它为浏览器与服务端的交互带来了
一种新的基础元素,为创建一种能够提供真正的交互性体验的Web应用提供了必要的基础。
早期的Web技术都是基于HTTP协议而发展起来的,而HTTP只是一个简单的基于请求 —— 响应操作的协议,所有的请求都是
由客户端发起的。这套框架原本足以满足用户的需求,但在如今开发者所设计的web应用中,由客户端发起通信这种方式有着很大
的制约。虽然人们提出了各种临时方案,但它们都是基于HTTP协议的,只是应用了轮询或长轮询技术(例如Comet)。Comet能够让负责处理请求的线程得到释放,以防止服务器资源耗尽。由于轮询这种机制并不可靠,因此在2007年时,有人提出了一种名为
WebSocket的全双工(full-duplex)类型的通信方式。这项提议用了整整4年的时间才成为一个标准。但是,尽管它已成为一种标
准,但它的使用率却相当有限。WebSocket是在TCP/IP协议之上创建的一种帧协议,客户端将通过向服务器发送一种特殊的HTTP
请求以启动WebSocket。在最初的握手过程之后,客户端与服务器就能够*地以异步方式互相进行帧的传送了。帧分为两种类
型:即控制帧与数据帧。最小的控制帧仅有2比特的大小,而在数据帧方面,客户端的数据帧最小为6比特,服务端的数据帧最小为2
比特。数据帧既可以是文本型,也可以是二进制的。文本帧都经过了UTF-8的编码。帧可以实现分块,因此一个大数据集可以分解
为多个帧。WebSocket不会为帧附加任何标识信息,因此不同类型的信息对应的帧不可混用。只有控制帧能够在处理一个大消息时
的一系列中间帧中出现。在这些基础的帧之上,还可以定义更复杂的协议。比方说,一个帧能够带有校验和或是它的序列号等相关
信息。
WebSocket的API
WebSocket并不限定于仅在某个特定的编程语言、系统或是操作系统中使用。多数主流的编程语言以及许多浏览器都已开始支
持WebSocket的编程。虽然在不同的平台与编程语言中存在着大量的标准,但本文仅关注JavaScript HTML5以及Java(J2EE)对
WebSocket的支持。在浏览器这方面有两种实现标准,其最新版本分别为Hixie-76和HyBi-17(不久之后发展为IETF RFC 6455)。
HyBi的实现相对更高级,并且得到了目前所有主流浏览器的支持。而在服务端方面,基于Java的实现则是目前最为流行的。早些时
候在Java上曾经出现过几种WebSocket的实现,它们之后已发展为JSR 356这种实现。JSR代表Java规范请求,对规范请求的说明
有帮于让之后的各种实现保持一致性,并且易于使用。JSR也让开发者不必依赖于某个特定的实现。JSR 356与servlet规范是相互分
离的,但它也允许开发者访问某些servlet对象。JSR 356的内容涵盖了WebSocket连接的客户端与服务端, 我们稍后的讨论将集中
于配合浏览器端的JavaScript所实现的服务端。JSR 356目前属于J2EE 7的一部分,所有流行的开源Java应用服务器都支持它,包
括Tomcat、Jetty、Glassfish以及TJWS等等。除此之外,在Java环境中还存在着大约20种各自独立的WebSocket服务端解决方案,
其中有些方案也支持JSR 356。由于WebSocket是J2EE 7的一部分,因而在由Oracle与IBM所推出的商业应用服务器上同样也得到
支持。
正如我之前所说,WebSocket是一种消息传递协议。它的API提供了各种在通信双方进行消息传递与接收的方法。这里并不存
在经典的订阅者与发布者的关系。消息只有两种类型,即文本型与二进制型。不过,在这些类型的消息处理函数中可以对消息进行
逻辑上的分离。在Java中能够以某种方式处理被分解为多个块的部分消息,JavaScript尚未支持这种程度的控制能力。如同之前所
说,WebSocket是一种非常泛用的协议,它可以在握手时指定所需的逻辑子协议。当不同的系统能够验证所连到的系统支持这种逻
辑子协议及扩展时,使用WebSocket进行系统集成就变得容易很多。WebSocket帧格式允许在它的基础上使用可协商的扩展,这与
意味着一般来说帧可能会提供更多的信息,并且可能会引入不同的帧类型。
WebSocket对于以下类型的应用程序的开发是一种非常自然的选择:
需要玩家之间实时协作的游戏
实时监控系统
需要用户进行协作的系统,例如聊天、共享文档的编辑等等。
其实,WebSocket在传统的Web应用中也能够展现其优势。大多数Web应用都是基于请求 - 响应这一范式进行设计的。虽然
AJAX能够实现异步操作,但在继续处理下一步操作之间,仍然必须等待响应返回。而由于WebSocket连接只需建立一次,从而避免
了为每次数据交换重建连接的过程,并且在后续的通信中也无需发送多余的HTTP头信息。这种优势在SSL类型的连接上体现得尤为
明显,因为最初的连接握手是一个开销很大的操作。浏览器端的WebSocket发送操作是完全异步的,而Java的服务端代码在发送消
息后无需进行等待。由于发送消息的这种*度,在应用中或许需要对某些操作进行手动记录,以保持应用状态的一致性。在使用
WebSocket时也能够模拟请求 - 响应这一范式,但如此一来,WebSocket作为一种真正的异步双向消息传递系统的优势也被大大消
减了。由于以上所描述的这些特性,因此应当鼓励开发者在某些场景中对应用程序的设计方式进行重新思考。
假设某一个应用程序包含了复杂的用户界面,其中某些区域的功能需要通过服务端的大量计算才能够生成对应的内容。传统的
基于AJAX的实现方式可以选择一种延迟调用的机制,通过某个内容请求调用以生成这一区域的内容。而在使用WebSocket的场合
下,服务端可以在浏览器做好准备的情况下直接发送内容,而无需对某个AJAX请求进行响应。AJAX请求这一方式的缺陷在于,由
于浏览器所发送的请求是串行的,因此服务端的处理过程无法针对请求的顺序进行相应的优化。而WebSocket为服务端提供了一个
自行决定最佳的内容生成方式的机会,因而能够提升Web应用的整体响应性。
要用效地利用WebSocket的功能,还需要仔细考虑几个额外的要点。由于在WebSocket中随时可能出现网络连接的丢失,使数
据无法正确地传递,因此对于一些至关重要的数据需要进行一些额外的手动记录操作。一般来说,所收到的每条消息都必须提供足
够的信息,以指示如何对其进行处理。但没有有效的手段能够了解信息的请求者是谁,是来自客户端的请求,还是说服务端想要更
新某些内容。在具体使用WebSocket的过程中,可能需要对Web应用的设计进行更深入的重新思考。此外,JavaScript代码的功能可
以迁移至服务端,打个比方,用户的输入可以立即发送给服务端进行处理,通过这种方式能够实现一些复杂的数据校验操作,而这
些校验功能或许是JavaScript所无法处理的。用户的输入还能够即时地保存在后台系统中,因此浏览器就无需将最终的数据传递给服
务器进行额外的数据校验,因为数据在保存在后台期间已经经过了校验。如果要使某个应用从富Web客户端转为一种轻量级的客户
端,就可以考虑以这种方式增加服务端代码的职责。
使用WebSocket时所需注意的要点
在Web应用开发时使用WebSocket也会面对一些特别的挑战,WebSocket的Session与HTTP的Session之间并无任何关联,虽
然也可将其用作类似的目标。在Session中可以附加某些通用的数据,因此所有的消息处理过程都可以依赖于Session中所维护的某
些状态和数据。WebSocket的Session也可以根据空闲(不活跃)时间间隔的配置产生超时情况,正如HTTP Session一样。不过有
些系统会自动地持续发送Ping这一控制消息,以防止出现超时。JSR 356建议将HTTP Session与WebSocket Session的超时进行同
步。一旦HTTP Session超时,在其范围内所创建的所有WebSocket连接也都必须关闭。但有些Web应用的设计不会产生任何HTTP
Session,而有些应用的Session超时不依赖于HTTP Session,而是由JavaScript所管理的,因此这种机制并不能够进行可靠的推广。
另一种需要注意的要点在于,某些浏览器会维护一个连接池,以重用连接的方式访问相同的网站,因此这种流程可以被串行
化。而如果浏览器为WebSocket连接也创建一个连接池,那么它会受到严重的制约。因为如果没有某种机制保持WebSocket连接的
关闭,这个连接就永远处于活跃状态,而其它任何创建新连接的尝试都会产生死锁。因此,最佳实践的推荐做法是只使用一个
WebSocket连接。浏览器无法对通过WebSocket进行传递的数据进行缓存,因此通过WebSocket传递可以在浏览器中缓存的资源。
上一篇: jQuery取id有.的值的方法