WebSocket
1、什么是webSocket?
WebSocket是一种在单个
**TCP连接**
上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,
允许服务端主动向客户端推送数据
。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以
创建持久性的连接,并进行双向数据传输。

2、webSocket可以用来做什么?
利用双向数据传输的特点可以用来完成很多功能,不需要前端
轮询
,浪费资源。例如:
1、通告功能
2、聊天功能 (如下是逻辑图)
3、实时更新数据功能
4、弹幕
3、webSocket协议
本协议有两部分:握手和数据传输。
握手是基于http协议的。
GETws://localhost/chat HTTP/1.1Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: chat,superchat
Sec-WebSocket-Version:13
来自服务器的握手看起来像如下形式:
HTTP/1.1101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

4、服务端
maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>5.7.22</version></dependency>
WebSocket配置类
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.socket.server.standard.ServerEndpointExporter;/**
* @author Hao
* @date 2023-03-01 16:18
* @description:
* @version:
*/@ConfigurationpublicclassWebSocketConfig{/**
* 注入ServerEndpointExporter,
* 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
*/@BeanpublicServerEndpointExporterserverEndpointExporter(){returnnewServerEndpointExporter();}}
WebSocket操作类
通过该类WebSocket可以进行群推送以及单点推送
importorg.apache.logging.log4j.LogManager;importorg.apache.logging.log4j.Logger;importorg.springframework.stereotype.Component;importcn.hutool.core.util.StrUtil;importjavax.websocket.*;importjavax.websocket.server.PathParam;importjavax.websocket.server.ServerEndpoint;importjava.io.IOException;importjava.util.concurrent.ConcurrentHashMap;/**
* @author Hao
* @date 2023-03-01 16:18
* @description:
* @version:
*/@ServerEndpoint(value ="/websocket/{userId}")@ComponentpublicclassWebSocket{privatefinalstaticLogger logger =LogManager.getLogger(WebSocket.class);/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的
*/privatestaticint onlineCount =0;/**
* concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象
*/privatestaticConcurrentHashMap<String,WebSocket> webSocketMap =newConcurrentHashMap<>();/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/privateSession session;privateString userId;/**
* 连接建立成功调用的方法
*/@OnOpenpublicvoidonOpen(Session session,@PathParam("userId")String userId){this.session = session;this.userId = userId;//加入map
webSocketMap.put(userId,this);addOnlineCount();//在线数加1
logger.info("用户{}连接成功,当前在线人数为{}", userId,getOnlineCount());try{sendMessage(String.valueOf(this.session.getQueryString()));}catch(IOException e){
logger.error("IO异常");}}/**
* 连接关闭调用的方法
*/@OnClosepublicvoidonClose(){//从map中删除
webSocketMap.remove(userId);subOnlineCount();//在线数减1
logger.info("用户{}关闭连接!当前在线人数为{}", userId,getOnlineCount());}/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/@OnMessagepublicvoidonMessage(String message,Session session){
logger.info("来自客户端用户:{} 消息:{}",userId, message);//群发消息/*for (String item : webSocketMap.keySet()) {
try {
webSocketMap.get(item).sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}*/}/**
* 发生错误时调用
*
* @OnError
*/@OnErrorpublicvoidonError(Session session,Throwable error){
logger.error("用户错误:"+this.userId +",原因:"+ error.getMessage());
error.printStackTrace();}/**
* 向客户端发送消息
*/publicvoidsendMessage(String message)throwsIOException{this.session.getBasicRemote().sendText(message);//this.session.getAsyncRemote().sendText(message);}/**
* 通过userId向客户端发送消息
*/publicvoidsendMessageByUserId(String userId,String message)throwsIOException{
logger.info("服务端发送消息到{},消息:{}",userId,message);if(StrUtil.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
webSocketMap.get(userId).sendMessage(message);}else{
logger.error("用户{}不在线",userId);}}/**
* 群发自定义消息
*/publicstaticvoidsendInfo(String message)throwsIOException{for(String item : webSocketMap.keySet()){try{
webSocketMap.get(item).sendMessage(message);}catch(IOException e){continue;}}}publicstaticsynchronizedintgetOnlineCount(){return onlineCount;}publicstaticsynchronizedvoidaddOnlineCount(){WebSocket.onlineCount++;}publicstaticsynchronizedvoidsubOnlineCount(){WebSocket.onlineCount--;}}
测试controller
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.io.IOException;/**
* @author Hao
* @date 2023-03-01 16:18
* @description:
* @version:
*/@RestController@RequestMapping("/webSocket")publicclassWebSocketController{@AutowiredprivateWebSocket webSocket;@PostMapping("/sentMessage")publicvoidsentMessage(String userId,String message){try{
webSocket.sendMessageByUserId(userId,message);}catch(IOException e){
e.printStackTrace();}}}
5、webSocket网页客户端工具
http://websocket.jsonin.com/

复制三个tab
WebSocket地址分别输入后连接
ws://127.0.0.1:8051/websocket/1
ws://127.0.0.1:8051/websocket/2
ws://127.0.0.1:8051/websocket/3

通讯测试
1.往客户端发消息
127.0.0.1:8092/webSocket/sentMessage?userId=1&message=请进入视频会议
127.0.0.1:8092/webSocket/sentMessage?userId=2&message=请进入视频会议
127.0.0.1:8092/webSocket/sentMessage?userId=3&message=请进入视频会议


2.客户端收到消息回复“好的”
最后送所有正在努力的大家一句话:
你不一定逆风翻盘,但一定要向阳而生。
期待下次发布好的文章:
山水相逢,我们江湖见。
版权归原作者 江東-H 所有, 如有侵权,请联系我们删除。