WebSocket是个啥
态度明确点,这玩意儿是个协议。
从http1.1相较于http1.0增加的功能之一就是长连接(Persistent Connection),作用就是为了弥补http无法长时间保持活性的缺点,让以前只能通过轮询实现的功能看起来优雅一点。好嘛,原理上支持了之后,我这http里没有对应的协议咋办。WebSocket就来了。
WebSocket有啥特点
直接上图
相较于http请求多了几个东西:
Upgrade: websocket
Connection: Upgrade
请求用这俩告诉服务器,老子是websocket请求,你注意点,别给我割断喽。
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: pHl+HeJx5QV8NZuTw0xtYQ==
Sec-WebSocket-Version: 13
服务器:出示一下你的key以及您需要的服务类型Extensions,哦哦您是一三版的,欢迎欢迎~
Sec-WebSocket-Accept: iKC4KsGSKf4cna4SdMVX0rmjQik=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Upgrade: websocket
服务器:这是您今晚的身份卡请收好,这边请。
WebSocket的作用
websocket常用于实现数据更新的实时通知的业务场景。区别于ajax轮询,websocket只需要一次握手便能与服务器建立链接,而且信息由服务器端推送通知。
WebSocket代码实现
前端(vue组件):
<script>
const df = function (ms) {return function (e) {console.log(`webSocket---${ms}---webSocket---${e.data || ""}`)}}
export default {
name:"webConnection",
props:{
url:{
default:"",
type:String
},
onopen:{
default:df('开始链接'),
type:Function
},
onmessage:{
default:df('收到消息'),
type:Function
},
onclose:{
default:df('关闭'),
type:Function
},
one rror:{
default:df('发生错误'),
type:Function
}
},
data() {
return {
socket:null
}
},
computed:{
WebSocketUrl:function() {
let url = "";
this.url.includes('https') ?
url = this.url.replace(new RegExp(/https/),'wss') :
url = this.url.replace(new RegExp(/http/),'ws') ;
return url;
}
},
methods:{
Connect() {
if(typeof(WebSocket) === "undefined") return;
try {
this.socket = new WebSocket(this.WebSocketUrl);
this.socket.onopen = this.onopen;
this.socket.onmessage = this.onmessage;
this.socket.onclose = this.onclose;
this.socket.onerror = this.onerror;
console.log('连接成功');
} catch(err) {
console.log('连接失败');
}
},
sendMsg(msg) {
if(this.socket && this.socket.readyState === 1) {
this.socket.send(msg);
} else {
alert('暂无链接存在,请先建立连接')
}
},
reConnect() {
if(this.socket && this.socket.readyState === 1) {
this.disConnect();
}
this.Connect();
},
destoryConnect() {
this.disConnect();
this.socket = null;
},
disConnect() {
if(this.socket && this.socket.readyState !== 3) {
this.socket.close();
}
}
},
mounted() {
this.Connect();
},
render() {},
beforeDestroy() {
this.destoryConnect();
}
}
</script>
后端:
配置类
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
链接层
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
//@ServerEndpoint("/websocket/{user}")
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
try {
sendMessage("连接成功");
} catch (IOException e) {
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*
* @param session
* @param error
*/
@OnError
public void one rror(Session session, Throwable error) {
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
* */
public static void sendInfo(String message) throws IOException {
for (WebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}
接口层
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import com.xzs1.first.service.WebSocketServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value="/websocket")
public class webscoket {
@RequestMapping(value="/sendToOne", produces = {"application/json; charset=utf-8"},method=RequestMethod.POST)
public void sendToOne(HttpServletRequest request,String message){
String str = message;
try {
WebSocketServer.sendInfo(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
实现效果
(手动藏起报错)