2019独角兽企业重金招聘Python工程师标准>>>
1.1 Http和WebSocket
1.1.1 HTTP
http协议在通信过程中存在一个巨大的缺陷,通信只能由客户端发起,服务器只能根据响应返回响应的结果。也就说,服务器端无法主动给客户端发送消息。
对于服务器端连续的状态变化,http协议就显得有些力不从心了,当然也可以通过其他的方式实现。比如:
- 轮询(每隔一段时候,就发出一个询问,了解服务器有没有新的信息)
- long poll(采用阻塞模式,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始)。
虽然这样也可以实现我们的要求,但是资源就在轮询的过程中被大量浪费。
1.1.1 WebSocket
WebSocket协议,2008年诞生,2011年称为国际标准,其最大的特点就是服务器端可以主动向客户端发送消息,实现真正的双向平等对话。主要特点:
- 建立在tcp协议之上,服务器端的实现比较容易
- 与http协议有很好的兼容性,握手阶段采用http协议
- 数据格式比较轻量,性能开销小,通信高效
- 可以发送文本,也可以发送二进制
- 没有同源策略(htpp的同源策略主要是出于安全考虑)
- 协议标识是ws,如ws://127.0.0.1:8080/myHandler/{Id}"
理论没看懂的可以戳这 故事描述型
1.2 WebSocket工作方式
1.2.1 WebSocket 客户端
创建WebSocket
var Socket = new WebSocket(url, [protocol] );//协议可以为空
属性
Socket.readyState//连接状态
Socket.bufferedAmount //队列中等待传输,但是还没有发出的 UTF-8 文本字节数。
事件,编写的时候要加上on 比如onOpen
open //连接建立时触发
message //客户端接收服务端数据时触发
error //通信发生错误时触发
close //连接关闭时触发
方法
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("连接已关闭...");
};
1.2.2 WebSocket 服务器端
服务器端的就主要用代码来实现吧
2. 实践篇源码地址 密码:f28e
服务端获取消息很简单,主要是向服务器端发送消息。需要向客户端发送消息,那么我们需要知道客户端的某个唯一标识,那么这个标识用什么来表示呢,那就是session。
2.1 普通javaEE方式
直接贴码,里面注释很清晰 需要的依赖
java源码
package me.gacl.websocket;import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;/*** @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端*/
@ServerEndpoint("/websocket")
public class WebSocketTest {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识private static CopyOnWriteArraySet
}
2.2 spring boot集成
这里通过重新写一个controller,直接给客户端发送消息,先贴这里的代码,应该大部分人都是想实现这个功能。这里的目的是,在处理一个其他请求之后,需要给原来的客户端发送消息,告诉它我已经处理完了,收到消息之后再处理后续的逻辑(扫码场景比较普遍)。
@GetMapping("/")public WebsocketResponse sendSuccess(){MyHandler send = new MyHandler();TextMessage msg = new TextMessage("发给客户端");send.sendMessageToUser("888",msg);return new WebsocketResponse(1);}
有需要的直到源码中拉取代码吧,服务器端的原理都类似
2.2.1 代码注意问题
- 这里的session一定是需要回调的那个客户端的session,所以第一次请求是需要保存客户端的session,公司一般放在redis中缓存。