websocket
定义
背景
HTTP协议和HTTPS协议通信过程通常是客户端通过浏览器发出一个请求,服务器接受请求后进行处理并返回结果给客户端,客户端处理结果。
这种机制对于信息变化不是特别频繁的应用可以良好支撑,但对于实时要求高、海量并发的应用来说显得捉襟见肘
WebSocket出现前我们实现推送技术,用的都是轮询,在特定的时间间隔,浏览器自动发出请求,将服务器的消息主动的拉回来,这种情况下,我们需要不断的向服务器发送请求,并且HTTP 请求 的header非常长,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽和服务器资源,并且服务器不能主动向客户端推送数据。在这种情况下需要一种高效节能的双向通信机制来保证数据的实时传输,于是基于HTML5规范的WebSocket应运而生。
HTTP轮询
HTTP实现实时推送用到的轮询,轮询分两种:长轮询和短轮询(传统轮询)
短轮询
短轮询:浏览器定时向服务器发送请求,服务器收到请求不管是否有数据到达都直接响应 请求,隔特定时间,浏览器又会发送相同的请求到服务器, 获取数据响应,如图:
缺点:数据交互的实时性较低,服务端到浏览器端的数据反馈效率低
长轮询
长轮询:浏览器发起请求到服务器,服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断。如图:
缺点:服务器没有数据到达时,http连接会停留一段时间,造成服务器资源浪费,数据交互的实时性也很低
无论是长轮询还是短轮询,浏览器都要先发起对服务器的连接,才能接收数据,并且实时交互性很低。
概念
WebSocket是HTML5下一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的。
HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。
使用websocket有两种方式:1是使用sockjs,2是使用h5的标准。使用Html5标准自然更方便简单.
实现过程
- 创建WebSocket
- HTTP请求发送到服务器以发起连接
- 取得服务器响应后,建立的连接使用HTTP升级,从HTTP协议交换为WebSocket协议(使用标准的HTTP服务器无法实现WebSocket,只有支持这种协议的专门服务器才能正常工作。)
- 一旦WebSocket连接建立后,后续数据都以帧序列的形式传输
特点
- WebSocket在建立握手连接时,数据是通过http协议传输的,
- 在建立连接之后,真正的数据传输阶段是不需要http协议参与的。
- WebSocket是类似Socket的TCP长连接通讯模式。
- 在客户端断开WebSocket连接或Server端中断连接前,不需要客户端和服务端重新发起连接请求。
- WebSocket的send函数在实现中最终都是通过TCP的系统接口进行传输的。
- WebSocket是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动请求。
- 支持双向通信,实时性更强。
- 更好的二进制支持。
- 较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
- 支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
- 基于多线程或多进程的服务器无法适用于 WebSockets,因为它旨在打开连接,尽可能快地处理请求,然后关闭连接。
- 任何实际的 WebSockets 服务器端实现都需要一个异步服务器。
WebSocket与TCP,HTTP的关系
WebSocket与http协议是基于TCP的–可靠的协议–应用层
HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。简单地说,我们有一个非常快速的 接线员(Nginx) ,他负责把问题转交给相应的 客服(Handler) 。
具体关系如下:
组成结构
WebSocket 客户端
在客户端,没有必要为 WebSockets 使用 JavaScript 库。
实现 WebSockets 的 Web 浏览器将通过 WebSockets 对象公开所有必需的客户端功能(主要指支持 Html5 的浏览器)。
客户端 API
以下 API 用于创建 WebSocket 对象。
var Socket = new WebSocket(url, [protocol] );
以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
WebSocket 属性
以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:
属性 描述
Socket.readyState 只读属性 readyState 表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。
Socket.bufferedAmount 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。
WebSocket 事件
以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:
事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发
WebSocket 方法
以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:
方法 描述
Socket.send() 使用连接发送数据
Socket.close() 关闭连接
示例
// 初始化一个 WebSocket 对象
var ws = new WebSocket(‘ws://localhost:9998/echo’);
// 建立 web socket 连接成功触发事件
ws.onopen = function() {
// 使用 send() 方法发送数据
ws.send(‘发送数据’);
alert(‘数据发送中…’);
};
// 接收服务端数据时触发事件
ws.onmessage = function(evt) {
var received_msg = evt.data;
alert(‘数据已接收…’);
};
// 断开 web socket 连接成功触发事件
ws.onclose = function() {
alert(‘连接已关闭…’);
};
WebSocket 服务端
WebSocket 在服务端的实现非常丰富。
Node.js、Java、C++、Python 等多种语言都有自己的解决方案。
Java
Java 的 web 一般都依托于 servlet 容器。
servlet 容器有
Tomcat、Jetty、Resin。
其中 Tomcat7、Jetty7 及以上版本均开始支持 WebSocket(推荐较新的版本,因为随着版本的更迭,对 WebSocket 的支持可能有变更)。
Spring 框架对 WebSocket 也提供了支持。
Spring
Spring 对于 WebSocket 的支持基于下面的 jar 包:
org.springframework
spring-websocket
${spring.version}
在 Spring 实现 WebSocket 服务器步骤:
- 创建 WebSocket 处理器
扩展 TextWebSocketHandler 或 BinaryWebSocketHandler ,可以覆写指定的方法。
Spring 在收到 WebSocket 事件时,会自动调用事件对应的方法。
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
public class MyHandler extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// …
}
}
WebSocketHandler
public interface WebSocketHandler {