目录
一、项目介绍
如何实现实时同步对局?
二、WebSocket
1、什么是WebSocket?
2、WebSocket的报文格式
opcode
payload len
payload data
3、WebSocket握手过程
4、WebSocket代码的简单编写
三、WebSocket 和 HTTP的关系
1、相同点:
2、不同点
3、联系
一、项目介绍
五子棋双人对战项目一个Web项目,支持多个玩家联网匹配对局,主要有以下三个模块:
1、用户模块
用户的注册和登录。
管理用户的天梯分数、比赛场数、获胜场数。
2、匹配模块
依据用户的天梯积分,实现匹配机制。
3、对战模块
把两个匹配到的玩家放到一个游戏房间中。双方通过网页的形式进行对战。
关键技术:
Java,Spring/Spring Boot/Spring MVC,HTML/CSS/JS/AJAX,MySQL/MyBatis,WebSocket
如何实现实时同步对局?
之前学习的服务器开发,主要使用的是下面这样的模型:
客户端:主动向服务器发起请求,服务器收到之后,返回一个响应。如果客户端不向服务器发送请求,服务器就不会给客户端返回响应。
五子棋项目是要实现实时同步对局的,也就是对方落子后,我这边立马能更新棋盘,我落子后,对方也要能立即更新棋盘。
基于之前学过的HTTP协议,如果我不向服务器发起请求,拿到最新棋盘数据,那么我这里的页面就一直不会改变。
基于上面的问题,想到有以下2种解决方案:
1、客户端每隔一段时间向服务器发起请求,拿到最新的数据。
2、服务器主动给我们返回响应。
第一个方案明显不行,如果间隔时间太短,发送请求的频率会非常高,也就意味着会浪费带宽,浪费资源;间隔时间太长,就可能导致对方已经落子了,但还在间隔时间中,那么我就要继续等客户端发起请求才能拿到最新的数据,明显也不合理。
第二个方案可行,如果对方落子了,服务器接收到请求,主动给我返回响应,这很就合理了。
服务器主动发送响应给客户端,这样的场景称之为:消息推送。
那HTTP协议是否能实现 “消息推送” 场景呢?HTTP自身是难以实现这种消息推送效果的。如果要想实现这样的效果,就需要基于 “轮询” 的机制。而所谓的 “轮询” ,也就是上面的第一种方案,明显是不合理的,会白白浪费很多机器资源(尤其是带宽)。
但有一种协议可以很轻松的实现轮询:WebSocket。
二、WebSocket
1、什么是WebSocket?
1、WebSocket 是HTML5下一种新的协议(WebSocket协议本质上是一个基于TCP的协议)
2、它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽,同时可以达到实时通讯的目的。
3、WebSocket是一个持久化的协议。
2、WebSocket的报文格式
opcode
描述了当前这个WebSocket报文是啥类型。比如:
表示当前这是一个文本帧,还是一个二进制;
表示当前这是一个 ping 帧,还是一个 pong 帧。
payload len
表示当前数据报携带的数据载荷长度。
这个字段本身就是一个变长的,一个WebSocket数据报能承载的载荷长度是非常长的。
payload data
实际报文要传输的数据载荷。
3、WebSocket握手过程
使用网页端,尝试和服务器建立 WebSocket 连接,网页端会先给服务器发起一个 HTTP 请求,这个 HTTP 请求中会带有特殊的 header:
Connection:Upgrade
Upgrade:WebSocket
如果服务器支持 WebSocket,就会返回一个特殊的 HTTP 响应。这个响应的状态码是 101(切换协议)。
然后客户端和服务器之间就可以开始使用 WebSocket 来进行通信了。
4、WebSocket代码的简单编写
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
后端代码:
@Component
public class TestWebSocket extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("建立连接");
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.out.println("收到信息: " + message.getPayload());
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.out.println("出现异常");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("关闭连接");
}
}
指定路径:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private TestWebSocket testWebSocket = new TestWebSocket();
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(testWebSocket, "/test");
}
}
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TestWebSocket</title>
</head>
<body>
<input type="text" id="message">
<button id="submit">提交</button>
<script>
//创建websocket实例
var websocket = new WebSocket("ws://127.0.0.1:8080/test");
//需要挂载一些实例
websocket.onopen = function() {
console.log("连接建立");
}
websocket.onmessage = function(e) {
console.log("接收消息: " + e.data);
}
websocket.onerror = function() {
console.log("连接异常");
}
websocket.onclose = function() {
console.log("连接关闭");
}
//实现点击按钮后,通过WebSocket发送请求
var input = document.querySelector("#message");
var button = document.querySelector("#submit");
button.onclick = function() {
console.log("发送信息: " + input.value);
websocket.send(input.value);
}
</script>
</body>
</html>
运行程序:
连接成功后,前端、后端都打印建立连接
输入信息,点击提交
关闭浏览器,后端打印
这就是简单的WebSocket通信过程。
三、WebSocket 和 HTTP的关系
1、相同点:
1、都基于 TCP,都是可靠性传输协议。
2、都是应用层协议。
2、不同点
1、WebSocket 是双向通信协议,模拟Socket协议,可以双向发送或接收信息。
2、HTTP 是单向的。
3、WebSocket 是需要浏览器和服务器握手进行建立连接的。
4、HTTP是浏览器向服务器发起请求,从而建立连接,服务器预先并不知道这个连接。
3、联系
WebSocket在建立握手时,数据是通过HTTP传输的。但是建立连接成功后,真正传输时是不需要HTTP协议的。