WebSocket
1 WebSocket概述
1)WebSocket是一种网络通信协议,是HTML5开始提供的一种在单个TCP连接上进行全双工通信的协议;是为了兼容现有浏览器的握手规范;
2)是一种浏览器与服务器进行全双工通信的网络技术,属于应用层协议,基于TCP传输协议,并复用HTTP的握手通道;
3)在 WebSocketAPI中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
4)浏览器通过 JavaScript向服务器发出建立 WebSocket连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP连接直接交换数据。
5)当获取 WebSocket连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
2 WebSocket与HTTP协议
1)HTTP协议只能由客户端发起通信,这种单向请求的特点,带来的问题是如果服务器有连续的状态变化,客户端获知非常麻烦,只能用轮询的方式,每隔一段时间,发出一个询问,了解服务器有没有新的信息,这种效率比较低,浪费资源;
2)websocket是一个持久化的协议;而HTTP是非持久化协议;
3)HTTP1.0生命周期是通过Request界定,一个Request一个Response,则请求就结束了;HTTP1.1中有一个keep-alive,在一个HTTP连接中,可以发送多个Request,接收多个Response,Response和Request对应的,且Response是被动的,不能主动发起;
4)http是一个无状态协议;
3 WebSocket特点
3.1 优点
1)服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种;
2)支持双向通信,实时性更强;
3)更好的二进制支持;
4)较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据长度),客户端到服务端的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
5)支持扩展。ws协议定义了扩展,用户可以扩展协议,或者事项自定义的子协议。(比如支持自定义压缩算法等)
3.2 举例
客户端发起:
服务端回复:服务端返回内容如下,状态代码101表示协议切换。到此完成协议升级,后续的数据交互都按照新的协议来
• Connection: Upgrade:表示要升级协议
• Upgrade: websocket:表示要升级到websocket协议。
• Sec-WebSocket-Version: 13:表示websocket的版本。如果服务端不支持该版本,需要返回一个Sec-WebSocket-Versionheader,里面包含服务端支持的版本号。
• Sec-WebSocket-Key:与后面服务端响应首部的Sec-WebSocket-Accept是配套的,提供基本的防护,比如恶意的连接,或者无意的连接。
4 WebSocket原理
4.1 其他方式的被动性
1)ajax轮询:让浏览器每隔几秒就发送一次请求,询问服务器是否有信息;
2)long poll:类似于ajax轮询,采取阻塞模型(一直打电话,没收到对方回应就不挂电话),客户端发起连接后,如果没信息,就一直不返回Response给客户端,直到有消息才返回,然后客户端再次建立连接;
3)websocket:只需要经过一次HTTP请求,就可以不断的互通消息;
4.2 websocket的产生
1)ajax轮询需要服务器有很快的处理速度和资源;long poll需要有很高的并发,及同时接待客户的能力;
2)websocket在服务器完成协议升级后(HTTP->websocket),服务端就可以主动推送消息给客户端;
3)只需要经过一次HTTP请求,就可以不断的互通消息;解决了服务器消耗资源以及同步延迟问题;
5 常用属性
5.1 @WebSocketEndpoint
注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端。注解的值将被用于监听用户连接的终端访问URL地址。
5.2 @onOpen
打开一个新连接,即有新连接时,会调用被此注解的方法。
5.3 @onClose
关闭连接时调用。
5.4 @onMessage
当服务器接收到客户端发送的消息时所调用的方法。
5.5 @PathParam
接收 uri参数的,与@PathVariable功能差不多,可通过url获取对应值
6 WebSocket 后端JAVA实现
6.1 pom文件依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
6.2 运行类
1)添加注解:
@EnableWebSocket
2)添加Bean:
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
6.3 WebSocket controller类
1)注解:
@ServerEndpoint(value = "/heartbeatMonitor/{userId}")
@Component
2)其他类注入方式:
3)方法使用:
以@ServerEndpoint(value = "/websocket/{usernick}")
为例
1. @OnOpen
2. public void onOpen(@PathParam(value = "usernick") String userNick,Session session) {
3. String message = "有新游客[" + userNick + "]加入聊天室!";
4. log.info(message);
5. WebSocketUtil.addSession(userNick, session);
6. //此时可向所有的在线通知 某某某登录了聊天室
7. WebSocketUtil.sendMessageForAll(message);
8. }
10. @OnClose
11. public void onClose(@PathParam(value = "usernick") String userNick,Session session) {
12. String message = "游客[" + userNick + "]退出聊天室!";
13. log.info(message);
14. WebSocketUtil.remoteSession(userNick);
15. //此时可向所有的在线通知 某某某登录了聊天室
16. WebSocketUtil.sendMessageForAll(message);
17. }
19. @OnMessage
20. public void OnMessage(@PathParam(value = "usernick") String userNick, String message) {
21. //类似群发
22. String info = "游客[" + userNick + "]:" + message;
23. log.info(info);
24. WebSocketUtil.sendMessageForAll(message);
25. }
27. @OnError
28. public void onError(Session session, Throwable throwable) {
29. log.error("异常:", throwable);
30. try {
31. session.close();
32. } catch (IOException e) {
33. e.printStackTrace();
34. }
35. throwable.printStackTrace();
36. }
6.4 测试
http://coolaf.com/tool/chattest
1)连接
2)发送消息