赞
踩
在开发智能预约系统中,我们经常会遇到这样一类需求:用户需要远程预约,预约屏需要实时显示会议预约信息或者实时预约顺序等实时变化的数据。对于此类需求,传统的请求方式就是轮询,就是客户端通过一定时间间隔以频繁请求方式向服务器发送请求,来保持客户端和服务器端的数据同步。但这种做法有一个很大的弊端:当客户端已固定频率向服务器发送请求时,服务器端的数据可能并没有更新,带来很多不必要的请求,浪费带宽,效率低下;不频繁的话,数据更新可能又不及时。
WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
第一次握手:客户端向服务器端发送SYN包,表示“请求建立新连接”,客户端进入SYN_SENT状态。
第二次握手:服务器端收到SYN包,确认客户端发送过来的报文有效,服务器能正常接收客户端发送的数据,并向客户端发送SYN + ACK包,表示“同意建立新连接”。服务器端进入SYN_RECV状态。
第三次握手:客户端收到服务器端的SYN+ACK包,随后向服务器端发送ACK确认包,表示“确认收到服务器端同意连接的信号”,客户端和服务器端进入ESTABLISHED状态,建立连接完成。
三次握手的过程中,只能由客户端主动向服务器端发送连接请求,而服务器端则是被动接受连接请求。通过三次握手,双方确保彼此能够正常建立连接,数据交互正常。
SYN:同步序列号,用于建立会话连接。
ACK:确认数据包。
SYN_SENT:请求连接状态。
SYN_RECV:数据接收状态。
ESTABLISHED:建立连接状态。
第一次挥手:客户端发起关闭连接请求,向服务器端发送FIN包,表示客户端不再接收发送数据,客户端进入FIN_WAIT_1状态。
第二次挥手:服务器端确认关闭连接请求,向客户端发送一个ACK确认报文,表示已经接收到客户端发送的关闭请求,服务器端进入CLOSE_WAIT状态。
第三次挥手:服务器端在发送完全部数据后,向客户端发送一个FIN包,表示不再接收发送数据,服务器端进入LAST_ACK。
第四次挥手:客户端收到服务器端发送的FIN包后,向服务器端发送一个ACK确认报文,表示客户端接受关闭连接请求,客户端进入超时等待状态。随后服务器端进入CLOSED状态,连接关闭完成。
四次挥手的过程中,任何一方都可以发起关闭请求,另一方则必须对其进行确认,确保双方都完成关闭连接。
FIN:结束报文。
FIN_WAIT_1:等待关闭确认状态。
CLOSE_WAIT:被动等待关闭状态。
LAST_ACK:等待确认状态。
CLOSED:关闭状态。
等待超时时间的作用:如果客户端发送完最后一个ACK包之后,就释放连接资源,一旦ACK在发送的过程中出现网络丢失的情况,服务器端没有收到确认消息,那么就会一直处于最后确认状态,无法关闭连接。等待超时状态可以很好的解决这个问题,服务器端没有收到ACK包后,会重新发送FIN包,此时客户端还处于连接状态,向服务器端重新发送ACK包。
- var websocket = null;
-
- // 判断当前浏览器是否支持WebSocket, ws对应的地址是远程服务器端的请求路径
- if ('WebSocket' in window) {
- websocket = new WebSocket("ws://localhost:8010/websocket"); // 客户端建立连接请求
- } else {
- console.error("不支持WebSocket");
- }
- @RestController
- @RequestMapping("/websocket")
-
- /*
- @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,注解的值将被用于监听设备连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端。
- */
- @ServerEndpoint(value = "/websocket/{macAddress}")
-
- public class WebSocketServer {
-
- @Autowired
- private reservationService reservation; // 预约信息Service层
-
-
- @Autowired
- private deviceService device; // 设备信息Service层
-
- /**
- * 设备MAC地址的Map集合,key:MAC地址,value:Session对象
- */
- private static Map<String, Session> sessionMap = new HashMap<String, Session>();
-
- @OnOpen
- public void onOpen(Session session, @PathParam("macAddress") String macAddress) {
-
- // 将设备添加到设备列表
- sessionMap.put(macAddress, session);
-
-
- // 从数据库中获取保存的预约信息
- List<Reservation> list= reservation.selectReservation();
-
- // 向设备发送预约数据
- sendMessageToDevice(macAddress,list);
-
-
- }
-
- }
- // 向特定设备发送消息------根据设备的唯一标识(MAC地址),向特定设备发送消息
- public static void sendMessageToDevice(String macAddress, List<Reservation> dataList) {
- Session session = devices.get(macAddress);
- if (session != null && session.isOpen()) {
- try {
-
- /*使用了Jackson库的ObjectMapper来将List 类型的数据转换为 JSON 格式。
- 在sendMessageToDevice方法中,我们将传入的 List 数据转换为 JSON 格式的字符串,并通过 WebSocket 发送给特定的设备。
- */
- String jsonData = objectMapper.writeValueAsString(dataList);
- session.getBasicRemote().sendText(jsonData);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- // 处理 WebSocket 连接
- websocket.on('connection', function connection(ws) {
-
- ws.on('open', function open() {
-
- console.log('已连接到服务器');
-
- // 在连接建立后,启动心跳定时器
- startHeartbeat();
- });
-
- // 接收消息
- ws.on('message', function incoming(message) {
-
- if(message === 'ok'){
-
- console.log('服务器端发送过来的数据是: %s', message);
-
- // 收到心跳消息,向服务器发送心跳回复消息
- sendHeartbeat();
-
- }else{
-
- // 将预约信息进行展示
-
- }
-
- });
-
- });
-
- function sendHeartbeat() {
- // 向服务器发送心跳回复消息
- ws.send('ok');
- }
-
- function startHeartbeat() {
- // 每隔一段时间发送一次心跳消息
- setInterval(() => {
- ws.send('ok');
- }, 10000); // 10秒发送一次心跳消息
- }
- @OnMessage
- public void onMessage(String message) {
-
- System.out.println("收到客户端发来的消息是: " + message);
-
-
- // 首先回复客户端处于运行状态
- if ("ok".equals(message)) {
-
- // 收到心跳消息,回复服务器端
- sendHeartbeat(session);
-
- } else {
- // 处理其他消息
-
- // 进行人脸识别操作
-
- // 二维码扫描验证操作
-
- // 密码验证操作等等
-
- }
-
- }
-
- private void sendHeartbeat(Session session) {
- try {
- session.getBasicRemote().sendText("ok");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- @OnClose
- public void onClose(Session session, @PathParam("macAddress") String macAddress) {
- // 将设备从设备列表中移除
- sessionMap.remove(macAddress);
-
- // 根据下线的设备MAC地址,修改数据库中设备的状态码----以便于后台系统实时监测设备的在线情况
- device.update(macAddress);
- }
基于Websocket的心跳机制来实现。Websocket的心跳机制是为了保持连接的稳定性和可靠性而设计的。在Websocket通信过程中,客户端和服务器之间会定期发送心跳消息来确认连接是否仍然有效。
具体的心跳机制可以通过以下步骤实现:
WebSocket 是一种在 Web 应用程序中实现双向通信的协议,它具有双向通信、持久连接、低延迟、安全性等特性,适用于实时应用程序和需要实时数据更新的场景。全双工通信以及持久性连接特点使得WebSocket在在线聊天、实时游戏、股票行情推送方面频繁使用,这些应用要求数据实时更新,每次通信不需要重新建立连接,减少了通信的开销并提高了通信效率。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。