写在前面
WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。作为单个TCP连接上进行全双工通信的通信协议,解决了Http客户端只能单向请求的缺点,使数据传输变得更加简单。
WebSocket的特点
Websocket作为一种服务端推送技术拥有诸多特点:
- 是基于TCP的应用层通信协议 ,区别于Http协议;
- 握手阶段采用HTTP协议 ,一次握手便可以建立连接;
- 相比于HTTP的完整头部信息,数据格式轻量,性能开销小
- 更好的二进制支持,可以发送文本,也可以发送二进制数据
- 没有同源限制,客户端可以与任意服务器通
WebSocket API
新建一个WebSocket对象
const ws = new WebSocket("ws://localhost:1111/websocket");
对象的事件
事件名称 | 事件作用 |
---|---|
onopen | 连接成功后的回调函数 |
onmessage | 客户端接收服务端数据时触发 |
onerror | 通信发生错误时触发 |
onclose | 连接关闭时触发 |
对象的方法
方法名称 | 方法作用 |
---|---|
send() | 发送数据 |
close() | 关闭连接 |
WebSocket应用场景
- IM在线聊天室
- APP扫码登录PC端
- 远程画板同步
- 大屏实时数据展示
- 在线选座
- 订单实时提醒
- …
WebSocket实例
以下是基于SpringBoot+Html5实现的WebSocket实例
1. IM聊天室
浏览器开两个客户端分别使用websocket发送消息
两个客户端都可以收到实时消息
当然这里只是做一个简单的演示,真正的IM中的用户存储,用户关系以及消息发送加密和页面优化都还要很多工作要做。
以下是代码的逻辑
/**
* 在线用户存储
*/
public static final Map<String, Session> ONLINE_USER_SESSIONS = new ConcurrentHashMap<>();
@OnOpen
public void openSession(@PathParam("username") String username, Session session) {
ONLINE_USER_SESSIONS.put(username, session);
String message = "欢迎⽤户[" + username + "] 来到聊天室!";
log.info("用户登录");
sendMessageAll(message);
}
@OnMessage
public void onMessage(@PathParam("username") String username, String message) {
sendMessageAll("⽤户[" + username + "] : " + message);
}
@OnClose
public void onClose(@PathParam("username") String username, Session session) {
//当前的Session 移除
ONLINE_USER_SESSIONS.remove(username);
//并且通知其他⼈当前⽤户已经离开聊天室了
try {
session.close();
} catch (IOException e) {
log.error("onClose error",e);
}
}
@OnError
public void onError(Session session, Throwable throwable) {
try {
session.close();
} catch (IOException e) {
log.error("onError excepiton",e);
}
log.info("Throwable msg "+throwable.getMessage());
}
public static void sendMessageAll(String message) {
ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, message));
}
public static void sendMessage(Session session, String message) {
if (session == null) {
return;
}
final RemoteEndpoint.Basic basic = session.getBasicRemote();
if (basic == null) {
return;
}
try {
basic.sendText(message);
} catch (IOException e) {
log.error("sendMessage IOException ",e);
}
}
- @ServerEndpoint("/chat-room/{username}") 定义服务端的订阅端点地址,客户端订阅此地址完成连接,然后通过onMessage进行消息发送