WebSocket技术革新:打造高效实时通信系统
开头还是说点废话吧。WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

从GitEE上搞了一个项目下来,然后精简和调整,尽量把代码调整到一看就懂。
项目就是普通的SpringBoot,没有用的东西全部移除,只需要一张表,当然也可以不用登陆,这样更精简。
核心代码就是ServerEndpoint的处理类:
-
- package boot.spring.service;
- import java.io.IOException;
- import java.util.Date;
- import java.util.concurrent.ConcurrentHashMap;
- import javax.websocket.OnClose;
- import javax.websocket.OnError;
- import javax.websocket.OnMessage;
- import javax.websocket.OnOpen;
- import javax.websocket.Session;
- import javax.websocket.server.PathParam;
- import javax.websocket.server.ServerEndpoint;
- import org.springframework.stereotype.Component;
- import com.alibaba.fastjson.JSON;
- import boot.spring.po.Message;
- @ServerEndpoint("/webSocket/{username}")
- @Component
- public class WebSocketServer {
- // concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
- private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();
- // 建立连接成功调用
- @OnOpen
- public void onOpen(Session session, @PathParam(value = "username") String userName) {
- // 链接建立,存储链接对象
- sessionPools.put(userName, session);
- // 广播上线消息
- Message msg = new Message();
- msg.setFrom("系统消息");
- msg.setDate(new Date());
- msg.setTo("0");
- msg.setText(userName);
- broadcast(JSON.toJSONString(msg, true));
- }
- // 关闭连接时调用
- @OnClose
- public void onClose(@PathParam(value = "username") String userName) {
- sessionPools.remove(userName);
- // 广播下线消息
- Message msg = new Message();
- msg.setFrom("系统消息");
- msg.setDate(new Date());
- msg.setTo("-2");
- msg.setText(userName);
- broadcast(JSON.toJSONString(msg, true));
- }
- // 收到客户端信息后,根据接收人的username把消息推下去或者群发
- // to=-1群发消息
- @OnMessage
- public void onMessage(String message) throws IOException {
- Message msg = JSON.parseObject(message, Message.class);
- msg.setDate(new Date());
- if (msg.getTo().equals("-1")) {
- broadcast(JSON.toJSONString(msg, true)); // -1群发
- } else {
- sendInfo(msg.getTo(), JSON.toJSONString(msg, true));
- }
- }
- // 错误时调用
- @OnError
- public void onError(Session session, Throwable throwable) {
- throwable.printStackTrace();
- }
- // 给指定用户发送信息
- public void sendInfo(String userName, String message) {
- Session session = sessionPools.get(userName);
- try {
- sendMessage(session, message);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- // 群发消息
- public void broadcast(String message) {
- for (Session session : sessionPools.values()) {
- try {
- sendMessage(session, message);
- } catch (Exception e) {
- e.printStackTrace();
- continue;
- }
- }
- }
- // 发送消息
- public void sendMessage(Session session, String message) throws IOException {
- if (session != null) {
- synchronized (session) {
- session.getBasicRemote().sendText(message);
- }
- }
- }
- public static ConcurrentHashMap<String, Session> getSessionPools() {
- return sessionPools;
- }
- }
复制代码
聊天室页面代码:
-
- <!DOCTYPE html>
- <html>
- <head>
- <title>聊天室</title>
- <link rel="stylesheet" href="./css/bootstrap.min.css" />
- <script src="./js/jquery-1.12.3.min.js"></script>
- <script src="./js/bootstrap.min.js"></script>
- <style>
- body {
- margin-top: 5px;
- }
- </style>
- </head>
- <body>
- <div>
- <p>登陆效果图如下,用aa,bb,cc登陆:</p>
-
- <p>三个人依次进入聊天室后效果如下,可以群发消息和点击登陆的用户私聊</p>
-
- <p>私聊时效果如下</p>
-
- </div>
- </body>
- </html>
复制代码
代码下载:
END
|