什么是websocket

有这样一种需求,怎么样才能在用户不做任何操作的情况下,网页能收到消息并发生变更。

最常见的解决方案是,网页的前端代码里不断定时发 HTTP 请求到服务器,服务器收到请求后给客户端响应消息。

又或者是长轮询。如果我们的 HTTP 请求将超时设置的很大,比如 30s,在这 30s 内只要服务器收到了扫码请求,就立马返回给客户端网页。如果超时,那就立马发起下一次请求。

本质上这些方法都是客户端主动去取数据,但场景复杂就不行了。

websocket是一个基于TCP,支持全双工通信的应用层协议。在使用 websocket 协议的网页游戏里,怪物移动以及攻击玩家的行为是服务器逻辑产生的,对玩家产生的伤害等数据,都需要由服务器主动发送给客户端,客户端获得数据后展示对应的效果。

如何建立websocket连接

浏览器在TCP三次握手建立连接之后,都统一使用HTTP协议先进行一次通信。

如果想建立websocket连接,就会在HTTP请求里带上一些特殊的header头。

1
2
3
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n

如果服务器正好支持升级成 websocket 协议。就会走 websocket 握手流程,同时根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串,放在 HTTP 响应的 Sec-WebSocket-Accept 头里,同时带上 101状态码「协议切换」,发回给浏览器。

之后浏览器也用同样的公开算法将base64码转成另一段字符串,如果这段字符串跟服务器传回来的字符串一致,则验证通过。

Websocket连接图解

WebSocket应用场景

  • 即时聊天通信
  • 多玩家游戏
  • 在线协同编辑/编辑
  • 实时数据流的拉取与推送
  • 体育/游戏实况
  • 实时地图位置

常用注解

来看一段具体的WS服务器类实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Component
@ServerEndpoint("/j2ee-ws/{msg}")
public class WebSocketServer {

//建立连接成功调用
@OnOpen
public void onOpen(Session session, @PathParam(value = "msg") String msg){
System.out.println("WebSocketServer 收到连接: " + session.getId() + ", 当前消息:" + msg);
}

//收到客户端信息
@OnMessage
public void onMessage(Session session, String message) throws IOException {
message = "WebSocketServer 收到连接:" + session.getId() + ",已收到消息:" + message;
System.out.println(message);
session.getBasicRemote().sendText(message);
}

//连接关闭
@OnClose
public void onclose(Session session){
System.out.println("连接关闭");
}

}

在以上代码中,我们着重关心 WS 相关的注解,主要有以下四个:

  1. @ServerEndpoint : 这里就像 RequestMapping 一样,放入一个 WS 服务器监听的 URL。
  2. @OnOpen :这个注解修饰的方法会在 WS 连接开始时执行。
  3. @OnClose :这个注解修饰的方法则会在 WS 关闭时执行。
  4. @OnMessage :这个注解则是修饰消息接受的方法,从Client接收消息时执行