简介:
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
以下 API 用于创建 WebSocket 对象。
var Socket = new WebSocket(url, [protocol] );
以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
WebSocket 属性
以下是 WebSocket 对象的属性。假定我们使用了以上代码创建了 Socket 对象:
属性 | 描述 |
---|---|
Socket.readyState | 只读属性 readyState 表示连接状态,可以是以下值:
|
Socket.bufferedAmount | 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。 |
WebSocket 事件
以下是 WebSocket 对象的相关事件。假定我们使用了以上代码创建了 Socket 对象:
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
WebSocket 方法
以下是 WebSocket 对象的相关方法。假定我们使用了以上代码创建了 Socket 对象:
方法 | 描述 |
---|---|
Socket.send() | 使用连接发送数据 |
Socket.close() | 关闭连接 |
WebSocket 实例
WebSocket 协议本质上是一个基于 TCP 的协议。
为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息"Upgrade: WebSocket"表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
使用案例
引入pom.xml
<!--添加websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
添加WebSocketConfig bean
package com.big.fly.webSocket;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* Created by 方文飞
* 2017-07-30 23:17
*/
@Component
/*
// 首先要注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint
注解声明的Websocket endpoint。要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器
,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
*/
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
添加WebSocket实现类package com.big.fly.webSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Created by 方文飞
* 2017-07-30 23:19
*/
@Component
@ServerEndpoint("/webSocket")
@Slf4j //https://www.cnblogs.com/weiapro/p/7633645.html File → settings → Plugins, 然后点击“Browse repositories” lombok
public class WebSocket {
private Session session;
private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this);
log.info("【websocket消息】有新的连接, 总数:{}"+ webSocketSet.size());
}
@OnClose
public void onClose() {
webSocketSet.remove(this);
log.info("【websocket消息】连接断开, 总数:{}"+ webSocketSet.size());
}
@OnMessage
public void onMessage(String message) {
log.info("【websocket消息】收到客户端发来的消息:{}"+ message);
}
public void sendMessage(String message) {
for (WebSocket webSocket: webSocketSet) {
log.info("【websocket消息】广播消息, message={}"+ message);
try {
webSocket.session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
添加一个html的界面用于测试
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<script src="/js/jquery-2.1.3.min.js" type="text/javascript"></script>
<head>
<meta charset="UTF-8"/>
<title>java method test</title>
</head>
<body>
<p id="websocket_Id"/>
<script>
//http://www.runoob.com/html/html5-websocket.html
/*WebSocket 协议本质上是一个基于 TCP 的协议。
为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,
这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息"Upgrade:
WebSocket"表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后
产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,
双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务
器端的某一方主动的关闭连接。
* */
var websocket = null;
if('WebSocket' in window) {
websocket = new WebSocket('ws:localhost:8081/webSocket');
}else {
alert('该浏览器不支持websocket!');
}
//连接建立时触发
websocket.onopen = function (event) {
console.log('连接建立时触发');
}
// 连接关闭时触发
websocket.onclose = function (event) {
console.log('连接关闭');
}
//客户端接收服务端数据时触发
websocket.onmessage = function (event) {
console.log('收到消息:' + event.data)
$("#websocket_Id").text(event.data)
}
//通信发生错误时触发
websocket.onerror = function () {
alert('websocket通信发生错误!');
}
window.onbeforeunload = function () {
websocket.close();
}
</script>
</body>
</html>
使用定时器测试WebSocket的双工特性A.启动类添加定时器注解
package com.big.fly;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling//在Spring Boot的主类中加入@EnableScheduling注解,启用定时任务的配置
public class FlyApplication {
public static void main(String[] args) {
SpringApplication.run(FlyApplication.class, args);
}
}
B.设置定时推送,通过tcp请亲将消息推送到前端
package com.big.fly.scheduled;
import com.big.fly.webSocket.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by Administrator on 2018/4/16.
*/
@Component
public class ScheduledTasks {
@Autowired
private WebSocket webSocket;
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss SSS");
@Scheduled(fixedRate = 50)
public void reportCurrentTime() {
webSocket.sendMessage("当前时间:" + dateFormat.format(new Date()));
System.out.println("当前时间:" + dateFormat.format(new Date()));
}
@Scheduled(cron="1 * * * * ? ")
public void reportCurrentTime1() {
System.out.println("当前时间一:" + dateFormat.format(new Date()));
}
@Scheduled(cron="1 * * * * ? ")
public void reportCurrentTime2() {
System.out.println("当前时间二:" + dateFormat.format(new Date()));
}
}
代码层级结构
启动项目测试