为什么需要 WebSocket?
- 因为 HTTP 协议有一个缺陷:通信只能由客户端发起
- 举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。
- 这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。
- 轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。
区别

引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
配置config
/**
* 开启WebSocket支持
* @author kewen
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
客户端
/**
* 该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。
*/
@ServerEndpoint("/websocket/{username}")
@Component
public class MyWebSocket {
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
*/
// private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
private static Map<String, MyWebSocket> map = new HashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
* tomcat
*/
private Session session;
@OnOpen
public void onOpen(Session session, @PathParam("username") String username) {
this.session = session;
map.put(username, this); // 加入set中
addOnlineCount(); // 在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("username") String username) {
map.remove(username); // 从set中删除
subOnlineCount(); // 在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
@OnMessage
public void onMessage(String msg, @PathParam("username") String username) throws IOException {
System.out.println("来自客户端的消息:" + msg);
msg = msg.trim();
if (msg.contains("@") && msg.startsWith("@") && msg.contains(":")) {
String name = "";
String[] split = msg.split(":");
if (split.length == 2) {
msg = split[1];
name = split[0].substring(1, split[0].length());
if (map.get(name) != null) {
map.get(name).sendMessage(username + ":" + msg);
this.sendMessage(username + ":" + msg);
} else {
this.sendMessage(username + ":你@的人不存在");
}
} else {
msg = "你发了个寂寞";
this.sendMessage(username + ":" + msg);
}
} else {
for (String s : map.keySet()) {
map.get(s).sendMessage(username + ":" + msg);
}
}
}
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
// this.session.getAsyncRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
MyWebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
MyWebSocket.onlineCount--;
}
}
客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HappyRoom</title>
<script>
var url = "ws://" + window.location.host + "/websocket/";
var ws = null;
//加入聊天室
function joinRoom() {
if (ws) {
alert("你已经在聊天室,不能再加入");
return;
}
var username = document.getElementById("user").value;
if (username==""){
alert("用户不能为空")
return;
}
ws = new WebSocket(url + username);
//与服务端建立连接触发
ws.onopen = function () {
alert("与服务器成功建立连接")
};
//服务端推送消息触发
ws.onmessage = function (ev) {
talking(ev.data);
};
//发生错误触发
ws.onerror = function () {
console.log("连接错误")
};
//正常关闭触发
ws.onclose = function () {
console.log("连接关闭");
};
}
//退出聊天室
function exitRoom() {
closeWebSocket();
}
function sendMsg() {
if(!ws){
alert("你已掉线,请重新加入");
return;
}
//消息发送
ws.send(document.getElementById("sendMsg").value);
document.getElementById("sendMsg").value = "";
}
function closeWebSocket() {
if(ws){
ws.close();
ws = null;
}
}
function talking(content) {
document.getElementById("content").append(content + "\r\n");
}
</script>
</head>
<body>
<div style="text-align: center;background-color: rgba(129,86,255,0.35);margin:0 auto;border:1px solid #000;width:600px;height:650px">
<br>欢迎使用<strong>bbox</strong>牌极简聊天室:<br/><br/>
<textarea id="content" cols="60" rows="30" readonly="readonly"></textarea><br>
<input type="text" id="sendMsg">
<button type="button" onclick="sendMsg()">发送消息</button>
<br/><br/>
用户:<input type="text" id="user">
<button onclick="joinRoom()">加入群聊</button>
<button onclick="exitRoom()">退出群聊</button>
</div>
</body>
</html>
版权声明:本文为qq_43419627原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。