- 使用演示
java
public static void main(String[] args) throws Exception{
//初始化socket客户端
BaseWebSocketClient socketClient = BaseWebSocketClient.init("传入链接");
//发送消息
socketClient.sendMessage("填写需要发送的消息", (receive) -> {
//这里编写接收消息的代码
});
}
只需要init后调用sendMessage方法即可,做到开箱即用。内部封装了失败重连接、断线重连接等功能。
基于Springboot工程
- 引入websocket依赖
java
<!--websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 开箱即用的工具类
java
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import java.io.IOException;
import java.net.URI;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 封装简易websocket客户端的类,带重连机制
*/
@ClientEndpoint
@Slf4j
public class BaseWebSocketClient {
/**
* 接收消息的函数,发送消息的时候传入
*/
private Consumer<String> receiveConsumer;
/**
* 连接socket的url,init的时候传入
*/
private String url;
/**
* 当前socket会话对象,init执行后生成
*/
private Session session;
/**
* 重连延迟2.5秒执行(连接需要时间,重连的时候延迟执行)
*/
private final Long reconnectTime = 2500L;
/**
* 重连次数
*/
private AtomicInteger retryReconnectCount = new AtomicInteger(0);
/**
* 发送消息重试次数
*/
private AtomicInteger reconnectSendCount = new AtomicInteger(0);
/**
* 发送消息最大重试次数
*/
private final int maxReconnectSendCount = 10;
/**
* 初始化,初始化完才能正常使用
*
* @param url websocket连接的地址
*/
public static BaseWebSocketClient init(String url) throws Exception {
BaseWebSocketClient client = new BaseWebSocketClient();
URI uri = new URI(url);
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(client, uri);
client.setUrl(url);
return client;
}
/**
* 发送消息
*
* @param message 消息
* @param receiveConsumer 接收消息的函数
*/
public void sendMessage(String message, Consumer<String> receiveConsumer) {
if (session == null) {
throw new RuntimeException("socket还未初始化");
}
this.setReceiveConsumer(receiveConsumer);
try {
if (session.isOpen()) {
//如果是open状态就能够发送消息
session.getBasicRemote().sendText(message);
reconnectSendCount = new AtomicInteger(0);
} else {
//进行重连
this.reconnect();
//重连2s后重新发送消息
new Timer().schedule((new TimerTask() {
@Override
public void run() {
//为了防止重试次数过多,这里做一下限制,一直连接不成功的就不发消息了
if (reconnectSendCount.getAndIncrement() >= maxReconnectSendCount) {
return;
}
//再次重试发送消息
sendMessage(message, receiveConsumer);
}
}), reconnectTime + reconnectTime);
}
} catch (Exception e) {
log.error("socket发送消息失败,url:{}", url, e);
}
}
/**
* 手动关闭连接,当不使用的时候手动关闭,减少连接资源的损耗
*/
public void close() throws IOException {
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "正常关闭"));
}
@OnOpen
public void onOpen(Session session) {
this.session = session;
}
/**
* 接收消息,接收消息的响应动作由使用者在send的时候自行传入
*
* @param message 消息内容
*/
@OnMessage
public void onMessage(String message) {
receiveConsumer.accept(unicodeDecode(message));
}
/**
* 关闭时的操作,分为正常关闭和异常关闭,这里异常关闭的做重连操作
*/
@OnClose
public void onClose(CloseReason closeStatus) throws Exception {
if (closeStatus == null || closeStatus.getCloseCode() != CloseReason.CloseCodes.NORMAL_CLOSURE) {
log.info("socket连接异常关闭url:{},closeStatus:{}", closeStatus, url);
//重连
reconnect();
} else {
log.info("socket连接关闭:{}", url);
}
}
@OnError
public void onError(Throwable throwable) throws Exception {
log.error("socket连接异常,url:{}", url, throwable);
//重连
reconnect();
}
/**
* 重连机制
*/
private void reconnect() throws Exception {
if (session == null || session.isOpen()) {
return;
}
//schedule里的this不是当前client对象
Object that = this;
new Timer().schedule(new TimerTask() {
public void run() {
//如果是打开的就不执行重连
if (session.isOpen()) {
return;
}
log.info("当前socket重连次数:{},url:{}", retryReconnectCount.getAndIncrement(), url);
try {
URI uri = new URI(url);
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(that, uri);
retryReconnectCount = new AtomicInteger(0);
log.info("重连成功");
} catch (Exception e) {
log.error("socket重连失败,url:{}", url, e);
}
}
}, reconnectTime);
}
private void setReceiveConsumer(Consumer<String> receiveConsumer) {
this.receiveConsumer = receiveConsumer;
}
private void setUrl(String url) {
this.url = url;
}
/**
* unicode转中文
*/
public static String unicodeDecode(String string) {
if (StringUtils.isBlank(string)) {
return string;
}
Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
Matcher matcher = pattern.matcher(string);
char ch;
while (matcher.find()) {
ch = (char) Integer.parseInt(matcher.group(2), 16);
string = string.replace(matcher.group(1), String.valueOf(ch));
}
return string;
}
}