一、简介
- WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
- WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
- 在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
WebSocket 的最大特点:
服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话。
WebSocket 的其他特点:
- 建立在 TCP 协议之上,服务器端的实现比较容易。
- 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
Http与WebSocket的区别:
http协议是短链接,因为请求之后,都会关闭连接,下次重新请求数据,需要再次打开连接。WebSocket协议是一种长连接,只需要通过一次请求来初始化链接,然后所有的请求和响应都是通过这个TCP链接进行通信。
二、实现
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.启动项
@SpringBootApplication
public class Websocket02Application {
public static void main(String[] args) {
SpringApplication.run(Websocket02Application.class, args);
}
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3.配置文件
server.port=8888
4.ws内容
@ServerEndpoint("/websocket/{pageCode}")
@Component
public class WebSocket {
private static final String loggerName = WebSocket.class.getName();
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
public static Map<String, List<Session>> electricSocketMap = new ConcurrentHashMap<String, List<Session>>();
/**
* 连接建立成功调用的方法
*
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(@PathParam("pageCode") String pageCode, Session session) {
List<Session> sessions = electricSocketMap.get(pageCode);
if (null == sessions) {
List<Session> sessionList = new ArrayList<>();
sessionList.add(session);
electricSocketMap.put(pageCode, sessionList);
} else {
sessions.add(session);
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("pageCode") String pageCode, Session session) {
if (electricSocketMap.containsKey(pageCode)) {
electricSocketMap.get(pageCode).remove(session);
}
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
* @param session 可选的参数
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("websocket received message:" + message);
try {
// session.getBasicRemote().sendText("这是推送测试数据!您刚发送的消息是:"+message);
for (List<Session> s : electricSocketMap.values()) {
for (int i = 0; i < s.size(); i++) {
s.get(i).getBasicRemote().sendText("这是推送测试数据!您刚发送的消息是:" + message);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发生错误时调用
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
;
}
}
这个是后端,前端代码如下:
copy1.html
<html>
<head>
<meta charset="UTF-8"></meta>
<title>springboot项目WebSocket测试demo</title>
</head>
<body>
<h3>springboot项目websocket测试demo</h3>
<h4>测试说明</h4>
<h5>文本框中数据数据,点击‘发送测试’,文本框中的数据会发送到后台websocket,后台接受到之后,会再推送数据到前端,展示在下方;点击关闭连接,可以关闭该websocket;可以跟踪代码,了解具体的流程;代码上有详细注解</h5>
<br />
<input id="text" type="text" />
<button onclick="send()">发送测试</button>
<hr />
<button onclick="clos()">关闭连接</button>
<hr />
<div id="message"></div>
<script>
var websocket = null;
if('WebSocket' in window){
websocket = new WebSocket("ws://127.0.0.1:8888/websocket/1");
}else{
alert("您的浏览器不支持websocket");
}
websocket.onerror = function(){
setMessageInHtml("send error!");
}
websocket.onopen = function(){
setMessageInHtml("connection success!")
}
websocket.onmessage = function(event){
setMessageInHtml(event.data);
}
websocket.onclose = function(){
setMessageInHtml("closed websocket!")
}
window.onbeforeunload = function(){
clos();
}
function setMessageInHtml(message){
document.getElementById('message').innerHTML += message;
}
function clos(){
websocket.close(3000,"强制关闭");
}
function send(){
var msg = document.getElementById('text').value;
websocket.send(msg);
}
</script>
</body>
</html>
copy2.html
<html>
<head>
<meta charset="UTF-8"></meta>
<title>springboot项目WebSocket测试demo</title>
</head>
<body>
<h3>springboot项目websocket测试demo</h3>
<h4>测试说明</h4>
<h5>文本框中数据数据,点击‘发送测试’,文本框中的数据会发送到后台websocket,后台接受到之后,会再推送数据到前端,展示在下方;点击关闭连接,可以关闭该websocket;可以跟踪代码,了解具体的流程;代码上有详细注解</h5>
<br />
<input id="text" type="text" />
<button onclick="send()">发送测试</button>
<hr />
<button onclick="clos()">关闭连接</button>
<hr />
<div id="message"></div>
<script>
var websocket = null;
if('WebSocket' in window){
// http://121.36.17.178:8180/paas/android/webSocket/socketStatus/oHGOmxOBpbpeqGE5zdA04PBqbLcM/35993/23
websocket = new WebSocket("ws://127.0.0.1:8888/websocket/1");
}else{
alert("您的浏览器不支持websocket");
}
websocket.onerror = function(){
setMessageInHtml("send error!");
}
websocket.onopen = function(){
setMessageInHtml("connection success!")
}
websocket.onmessage = function(event){
setMessageInHtml(event.data);
}
websocket.onclose = function(){
setMessageInHtml("closed websocket!")
}
window.onbeforeunload = function(){
clos();
}
function setMessageInHtml(message){
document.getElementById('message').innerHTML += message;
}
function clos(){
websocket.close(3000,"强制关闭");
}
function send(){
var msg = document.getElementById('text').value;
websocket.send(msg);
}
</script>
</body>
</html>
整个项目的目录如下:
三、测试
启动项目后,打开浏览器,输入http://localhost:8888/copy1.html和http://localhost:8888/copy2.html,
如果连接成功后,出现如下画面
这时候我们在文本框输入发送的消息:Hello workd! ,效果如下:
在copy1中发送数据,copy2也收到了,还可以继续发送, copy2也会继续接收。证明是成功了。