介绍
WebSocket 协议是一种基于TCP的协议,用于在客户端和服务器之间建立持久连接,并且可以在这个连接上实时地交换数据。WebSocket协议有自己的握手协议,用于建立连接,也有自己的数据传输格式。
当客户端发送一个 WebSocket 请求时,服务器将发送一个协议响应以确认请求。在握手期间,客户端和服务器将协商使用的协议版本、支持的子协议、支持的扩展选项等。一旦握手完成,连接将保持打开状态,客户端和服务器就可以在连接上实时地传递数据。
WebSocket 协议使用的是双向数据传输,即客户端和服务器都可以在任意时间向对方发送数据,而不需要等待对方的请求。它支持二进制数据和文本数据,可以自由地在它们之间进行转换。
总之,WebSocket协议是一种可靠的、高效的、双向的、持久的通信协议,它适用于需要实时通信的Web应用程序,如在线游戏、实时聊天等。
使用
导入依赖
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.2</version>
</dependency>
工具一
package com.seekgenjs.position.util;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
@SuppressWarnings("all")
@Component
public class WebSocketClient {
Logger logger = LoggerFactory.getLogger(WebSocketClient.class);
private final String URI = "wss://xxxx/wss";
private final String User_Name = "xxx";
private final String Act_Login = "xxx";
private final String Act_Device = "xxxx";
@Resource
MyWebSocketClient myWebSocketClient;
//项目启动建立连接
@PostConstruct
public void init() {
try {
URI uri = new URI(URI);
org.java_websocket.client.WebSocketClient client = new org.java_websocket.client.WebSocketClient(uri) {
@Override
public void onOpen(ServerHandshake hand) {
logger.debug("{}_Connected to WebSocket server", URI);
send(login());
timer();
}
private void timer() {
// Send heartbeat packet every 30 seconds
logger.debug("{}_开始执行定时任务,Send heartbeat packet every 30 seconds", System.currentTimeMillis());
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
//发送心跳的业务代码
send(sendHeartbeat());
} catch (Exception e) {
//print the error log
e.printStackTrace();
}
}
}, 1000L * 3, 1000L * 25);
}
@Override
public void onMessage(String message) {
System.out.println(message);
handleMessage(message);
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("Connection closed");
logger.debug("{}_Connection closed", System.currentTimeMillis());
}
@Override
public void onError(Exception ex) {
ex.printStackTrace();
}
};
client.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
//登录
private String login() {
HashMap<String, Object> map = new HashMap<>();
map.put("act", Act_Login);
map.put("user_name", User_Name);
map.put("access_token", myWebSocketClient.getToken());
return JSON.toJSONString(map);
}
//心跳包
private String sendHeartbeat() {
logger.debug("{}_Send heartbeat packet", System.currentTimeMillis());
HashMap<String, Object> map = new HashMap<>();
map.put("act", Act_Device);
return JSON.toJSONString(map);
}
/**
* 处理接收数据
*
* @param message
*/
public void handleMessage(String message) {
System.out.println("{}_Received message: " + message);
}
}
工具二
package com.seekgenjs.position.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.seekgenjs.common.core.domain.R;
import com.seekgenjs.common.utils.DateUtils;
import com.seekgenjs.common.utils.JsonUtils;
import com.seekgenjs.common.utils.StringUtils;
import com.seekgenjs.common.utils.Threads;
import com.seekgenjs.common.utils.redis.RedisUtils;
import com.seekgenjs.mine.clinentVo.EquipmentInfo;
import com.seekgenjs.mqtt.MqttClientService;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
@SuppressWarnings("all")
@Component
public class HeartbeatWebSocketClient {
Logger logger = LoggerFactory.getLogger(HeartbeatWebSocketClient.class);
private boolean isClosed;
private Timer heartbeatTimer;
private WebSocketClient client;
@Resource
private WssCacheToken cacheToken;
public WebSocketClient init() throws Exception {
WebSocketClient client = new org.java_websocket.client.WebSocketClient(
new URI(WssConstant.WSS_URI)) {
@Override
public void onOpen(ServerHandshake serverHandshake) {
// 连接成功后 --执行登录操作 --发送心跳消息
send(login());
}
@Override
public void onMessage(String s) {
handleMessage(s);
}
@Override
public void onClose(int i, String s, boolean b) {
logger.error("{}:Connection closed", DateUtils.getTime());
// 连接关闭,停止心跳定时器
stopHeartbeat();
isClosed = true;
//重连
reconnection();
}
@Override
public void onError(Exception e) {
logger.error("{}:Connection error,reason:{}", DateUtils.getTime(),e.getMessage());
stopHeartbeat();
}
};
client.connect();
Threads.sleep(1000);
// 启动心跳定时器
startHeartbeat(client);
return client;
}
/**
* 断开重连
* 重试5次为未连接上,等待半小时
* @throws Exception
* @return
*/
public synchronized WebSocketClient reconnection(){
int i = 5;
WebSocketClient wsc = null;
while (i<5 && wsc!=null && !wsc.isOpen()){
i++;
try {
WebSocketClient oldClient = this.client;
if (null != oldClient) {
oldClient.close();
logger.info("关闭旧的websocket连接");
}
logger.info("打开新的websocket连接,并进行认证");
WebSocketClient newClient = init();
this.client = newClient;
this.isClosed = false;
wsc = newClient;
// 启动心跳定时器
startHeartbeat(newClient);
//return newClient;
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
}
}
Threads.sleep(1000*60*30);
if (wsc==null){
reconnection();
}
logger.info("重连成功");
return wsc;
}
/**
* 发送心跳包
*/
@Async
private void startHeartbeat(WebSocketClient socketClient) {
// 启动心跳定时器,每隔30秒发送一条心跳消息
this.heartbeatTimer = new Timer();
this.heartbeatTimer.schedule(new TimerTask() {
@Override
public void run() {
if (!isClosed) {
logger.info("websocket向服务端发送消息,消息内容:{}", "heartbeat");
HashMap<String, Object> map = new HashMap<>();
map.put("act", WssConstant.ACT_DEVICE);
socketClient.send(JSON.toJSONString(map));
}
}
}, 3000, 3000);
}
/**
* 停止心跳
*/
private void stopHeartbeat() {
// 停止心跳定时器
if (this.heartbeatTimer != null) {
this.heartbeatTimer.cancel();
this.heartbeatTimer = null;
}
}
/**
* 登录
* @return
*/
private String login() {
logger.info("{}:wss 登录", DateUtils.getTime());
HashMap<String, Object> map = new HashMap<>();
map.put("act", WssConstant.ACT_LOGIN);
map.put("user_name", WssConstant.USER_NAME);
map.put("access_token", "token");
return JSON.toJSONString(map);
}
/**
* 处理接收数据
*
* @param message
*/
public void handleMessage(String message) {
}
}