一 什么是WebSocket
1.1 首先分清几个概念
PS:别的应用层协议也能通过tcp进行,那么这协议在底层也进行三次握手。
1.2 混淆点
- WebSocket:基于TCP的,运行在应用层,替代
http 的一个协议。 - 网上说的
WebSocket 只有一次握手,指的是:客户端发送一个http 请求到服务器,服务器响应后标志这个连接建立起来。而不是指TCP 的三次握手。
1.3 优点
- 节约宽带。轮询服务端数据的方式,使用的是http协议,head的信息很大,有效数据占比低,而使用WebSocket,头信息很小,有效数据占比高。
- 无浪费。轮询方法可能轮询10次,才可能碰到服务端数据更新,那么前9次数据都浪费了。而WebSocket是由服务器主动发回,来的都是新数据。
- 实时性。当服务器完成协议升级后(HTTP->Websocket),服务端可以主动向客户端推送信息,省去了客户端发起请求的步骤,同时没有间隔时间,只要服务端内容有变化,就可以告知客户端。实时性大大提高。
二 Socket和WebSocket的区别
三 WebSocket服务端搭建
3.1 导入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
3.2 搭建websocket服务
-
WebSocketConfig package com.wyq.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
-
WebSocketServer 用于接收客户端的webSocket 请求,处理主要逻辑。代码如下:
- @ServerEndpoint注解中写上客户端连接的地址。
package com.wyq.websocket.component;
import cn.hutool.json.JSONObject;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
@ServerEndpoint("/webSocket/{username}")
public class WebSocketServer {
private static Map<String, Session> clients = new ConcurrentHashMap<>();
@OnOpen
public void onOpen(@PathParam("username") String username, Session session) throws IOException {
if (username == null) {
return;
}
clients.put(username, session);
System.out.println("用户:" + username + "已连接到websocke服务器");
}
@OnClose
public void onClose(@PathParam("username") String username) throws IOException {
clients.remove(username);
System.out.println("用户:" + username + "已离开websocket服务器");
}
@OnMessage
public void onMessage(String json) throws IOException {
System.out.println("前端发送的信息为:" + json);
JSONObject jsonObject = new JSONObject(json);
String user = jsonObject.getStr("user");
String msg = jsonObject.getStr("msg");
Session session = clients.get(user);
if (session != null) {
sendMessageTo(msg,session);
} else {
System.out.println("对方不在线,对方名字为:" + user);
}
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
public void sendMessageTo(String message, Session session) throws IOException {
session.getBasicRemote().sendText(message);
}
}
3.3 第三方网站测试
-
在线测试网址
http://www.websocket-test.com/
-
连接url
ws://localhost:8080/webSocket/小王
-
建立、断开连接测试 -
模拟小王和小李通信
-
小王给小李发
{“msg”:“你好,我是小王”,“user”:“小李”}
-
小李收到后给小王发
{“msg”:“你好你好,我是小李”,“user”:“小王”}
-
小王页面显示 -
小李页面显示
四 客户端搭建
4.1 html页面
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/index.js" type="text/javascript"></script>
<meta charset="UTF-8">
<title>客户端</title>
<base target="_blank">
</head>
<body>
<h1>用户小王</h1><br/>
<button onclick="buttonCreate()">与服务器建立websocket链接</button>
<button onclick="buttonClose()">关闭websocket链接</button>
<p>链接状态:</p>
<h1 id="status">未建立链接</h1>
<p>给用户小李发送信息:</p>
<form method="post" action="/server" target="nm_iframe">
<label>目标用户:</label>
<input name = "user" placeholder="请输入接收信息的用户名"/>
<label>信息:</label>
<input name = "msg" placeholder="请输入信息"/>
<input type="submit" id="id_submit" name="nm_submit" value="发送" onclick="changeNum()"/>
</form>
<p>从服务器发来的信息:</p>
<h1 id="message"></h1>
</body>
</html>
4.2 js配置
index.js
var websocket = null;
var host = document.location.host;
var username = "${loginUsername}";
if ('WebSocket' in window) {
alert("浏览器支持Websocket")
username = "小王";
} else {
alert('当前浏览器 Not support websocket')
}
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
function buttonCreate() {
try {
websocket = new WebSocket('ws://' + host + '/webSocket/' + username);
initWebSocket();
}catch (e){
alert(e);
}
}
function buttonClose() {
try{
websocket.close();
}catch (e){
alert(e)
}
}
function initWebSocket() {
websocket.onerror = function() {
setMessageInnerHTML("WebSocket连接发生错误");
};
websocket.onopen = function() {
changeStatus("WebSocket连接成功");
}
websocket.onmessage = function(event) {
setMessageInnerHTML(event.data);
}
websocket.onclose = function() {
changeStatus("WebSocket连接关闭");
}
window.onbeforeunload = function() {
try {
websocket.close();
}catch (e){
alert(e);
}
}
}
function changeStatus(text) {
document.getElementById("status").innerText = text;
}
4.3 controller模拟信息发送
ServerController.java
package com.wyq.websocket.controller;
import cn.hutool.json.JSONObject;
import com.wyq.websocket.component.WebSocketServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@RestController
public class ServerController {
@RequestMapping(value = "/server", method = {RequestMethod.POST, RequestMethod.GET})
public void server(HttpServletRequest request) throws IOException {
try {
String msg = request.getParameter("msg");
String user = request.getParameter("user");
WebSocketServer ws = new WebSocketServer();
JSONObject jsonObject = new JSONObject();
jsonObject.put("user", user);
jsonObject.put("msg", msg);
String message = jsonObject.toString();
ws.onMessage(message);
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
4.4 运行测试
-
小王界面 -
小李界面 五 源码下载 github源码下载地址:
https://github.com/Ricardo0324/SpringBoot-WebSocket-Demo
|