使用webSocket实现对数据的实时推送
使用webSocket实现对数据的实时推送详解
1.什么是webSocket?
相对于 HTTP 这种非持久的协议来说,websocket是 HTML5 出的一个持久化的协议。
2.实时推送数据的实现方式以及应用场景
实现方式
1.轮询:客户端通过代码定时向服务器发送AJAX请求,服务器接收请求并返回响应信息。
优点:代码相对简单,适用于小型应用。
缺点:在服务器数据没有更新时,会造成请求重复数据,请求无用,浪费带宽和服务器资源。
2.长连接:在页面中嵌入一个隐藏的iframe,将这个隐藏的iframe的属性设置为一个长连接的请求或者xrh请求,服务器通过这种方式往客户端输入数据。
优点:数据实时刷新,请求不会浪费,管理较简洁。
缺点:长时间维护保持一个长连接会增加服务器开销。
3.webSocket:websocket是HTML5开始提供的一种客户端与服务器之间进行通讯的网络技术,通过这种方式可以实现客户端和服务器的长连接,双向实时通讯。
优点:减少资源消耗;实时推送不用等待客户端的请求;减少通信量;
缺点:少部分浏览器不支持,不同浏览器支持的程度和方式都不同应用场景:聊天室、智慧大屏、消息提醒、股票k线图监控等。
1. 为什么叫心跳包呢?
它就像心跳一样每隔固定的时间发一次,来告诉服务器,我还活着。2. 心跳机制是?
心跳机制是每隔一段时间会向服务器发送一个数据包,告诉服务器自己还活着,同时客户端会确认服务器端是否还活着,如果还活着的话,就会回传一个数据包给客户端来确定服务器端也还活着,否则的话,有可能是网络断开连接了。需要重连~3.实现心跳检测的思路:
每隔一段固定的时间,向服务器端发送一个ping数据,如果在正常的情况下,服务器会返回一个pong给客户端,如果客户端通过 onmessage 事件能监听到的话,说明请求正常,这里我们使用了一个定时器,每隔3秒的情况下,如果是网络断开的情况下,在指定的时间内服务器端并没有返回心跳响应消息,因此服务器端断开了,这个时候我们使用ws.close关闭连接,在一段时间后(在不同的浏览器下,时间是不一样的,firefox响应更快),可以通过 onclose事件监听到。因此在onclose事件内,我们可以调用 reconnect事件进行重连操作。
3.后台代码详解
MyWebSocket
package com.socket;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint(value = "/gpsDataPush")
@Component
public class MyWebSocket {
private static int onlineCount = 0;
private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
private Session session;
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this);
addOnlineCount();
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
try {
sendMessage("连接已建立成功.");
} catch (Exception e) {
System.out.println("IO异常");
}
}
@OnClose
public void onClose() {
webSocketSet.remove(this);
subOnlineCount();
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("来自客户端的消息:" + message);
}
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
/**
* 发送数据
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 发送数据
* @param message
* @throws IOException
*/
public static void sendAllMessage(String message) {
try {
webSocketSet = getWebSocketSet();
int i = 0 ;
webSocketSet.forEach(c->{
try {
c.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
});
}catch (Exception e){
System.out.println("socket 数据推送失败!");
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
MyWebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
MyWebSocket.onlineCount--;
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
public static CopyOnWriteArraySet<MyWebSocket> getWebSocketSet() {
return webSocketSet;
}
public static void setWebSocketSet(CopyOnWriteArraySet<MyWebSocket> webSocketSet) {
MyWebSocket.webSocketSet = webSocketSet;
}
}
TimeTask(定时任务)
package com.socket;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.model.ThingsData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 数据发送案例
*/
@Component
@EnableScheduling
public class TimeTask {
private static Logger logger = LoggerFactory.getLogger(TimeTask.class);
@Scheduled(cron = "0/15 * * * * ?")
public void test(){
}
}
ThingsData
package com.model;
import lombok.Data;
@Data
public class ThingsData {
//经度
private String jd;
//维度
private String wd;
//车辆状态
private String carState;
//速度
private String sd;
//风向
private String fx;
//高度
private String gd;
//gps编号
private String gpsNum;
public String getJd() {
return jd;
}
public void setJd(String jd) {
this.jd = jd;
}
public String getWd() {
return wd;
}
public void setWd(String wd) {
this.wd = wd;
}
public String getCarState() {
return carState;
}
public void setCarState(String carState) {
this.carState = carState;
}
public String getSd() {
return sd;
}
public void setSd(String sd) {
this.sd = sd;
}
public String getFx() {
return fx;
}
public void setFx(String fx) {
this.fx = fx;
}
public String getGd() {
return gd;
}
public void setGd(String gd) {
this.gd = gd;
}
public String getGpsNum() {
return gpsNum;
}
public void setGpsNum(String gpsNum) {
this.gpsNum = gpsNum;
}
}
4.使用websocket在线工具测试 ip+端口
WebSocket在线测试_在线模拟websocket请求工具