使用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请求工具