webSocket如何解决自动关闭的意思

时间:2025-04-20 17:34:34

我的前一篇文章“webSocket如何在自己的工程中使用?

地址:/jintingbo/article/details/80755636

讲述了webSocket的初级使用,初学者可以先看看那篇文章。

本文主要是解决webSocket自动关闭。

websocket它有一个“心跳”机制,但这个心跳机制是要程序自己去写代码实现的,websocket本身没有给你做这个东西。

它是如何自动关闭的呢?当电脑浏览器发送pong帧的时候,由于内容为空,于是服务器将空内容转发回去,导致客户端浏览器以为是错误的帧类型,发送关闭信息进行error关闭。(服务器返回时,必须要把它原来发来的东西发回去的,这是TCP/IP协议的要求)。

即然服务器接收到浏览器发送的"pong"后如果回复一个“pong”时,它会结束连接,那么为了避免这种事发生,可以在服务器接收到一个“pong”空信息时,不回复它的"pong",也就不关闭连接了。这是一种解决方案。

另一种解决方案是:当发生关闭时,可以主动发送心跳给对方,让连接复活,这样就相当于不断线了。本文就是用这个方案实现的。

第一步:在html文件中加入:
-----------------------------

<script type="text/javascript">
var ws;
//避免重复连接
var lockReconnect = false;
var wsUrl = "ws://localhost:8080/cl-market-camera-web/websocket";
createWebSocket(wsUrl);
function createWebSocket(url) {
try {
ws = new WebSocket(url);
initEventHandle();
} catch (e) {
                        //重新连接
reconnect(url);
}
}
        //封装websocket的那几个接口函数
function initEventHandle() {
= function () {
("连接关闭");
reconnect(wsUrl);
};
= function () {
("传输异常");
reconnect(wsUrl);
};
= function () {
//心跳检测重置
().start();
};

= function(event) {
                    //();

                    setMessageInnerHTML();
                    //如果获取到消息,心跳检测重置
                    ().start();
}
}
function reconnect(url) {
if(lockReconnect) return;
lockReconnect = true;
//没连接上会一直重连,设置延迟避免请求过多
setTimeout(function () {
    ("尝试重连..." + new Date().format("yyyy-MM-dd hh:mm:ss"));
    createWebSocket(url);
    lockReconnect = false;
}, 5000);
}
//心跳检测,每5s心跳一次
var heartCheck = {
timeout: 5000,
timeoutObj: null,
serverTimeoutObj: null,
reset: function(){
    clearTimeout();
    clearTimeout();
    return this;
        },
start: function(){
    var self = this;
    = setTimeout(function(){
        //这里发送一个心跳,后端收到后,返回一个心跳消息,
        //onmessage拿到返回的心跳就说明连接正常
        ("HeartBeat" + new Date().format("yyyy-MM-dd hh:mm:ss"));
                ("客户端发送心跳:" + new Date().format("yyyy-MM-dd hh:mm:ss"));

                 = setTimeout(function(){
                            //如果超过一定时间还没重置,说明后端主动断开了

                            ();
                            //如果onclose会执行reconnect,我们执行()就行了.
                            //如果直接执行reconnect 会触发onclose导致重连两次
                        }, )
                    }, )
                }
}
//js中格式化日期,调用的时候直接:new Date().format("yyyy-MM-dd hh:mm:ss")
= function(fmt) {
var o = {
    "M+" : ()+1,                 //月份 
    "d+" : (),                    //日 
    "h+" : (),                   //小时 
    "m+" : (),                 //分 
    "s+" : (),                 //秒 
    "q+" : ((()+3)/3), //季度
    "S"  : ()             //毫秒 
        }; 
        if(/(y+)/.test(fmt)) {

    fmt=(RegExp.$1, (()+"").substr(4 - RegExp.$)); 

                }

        for(var k in o) {
    if(new RegExp("("+ k +")").test(fmt)){
        fmt = (RegExp.$1, (RegExp.$==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
            }
                }
        return fmt; 
        }
function setMessageInnerHTML(innerHTML) {
('message').innerHTML += innerHTML + '<br/>';
}
</script>

第二步:在java的controller包中写一个WebSocketTest类
------------------------------
package ;
import .*;
import ;
import ;
import ;

@ServerEndpoint("/websocket")
public class WebSocketTest {
        //设置连接数
private static int onlineCount = 0;
private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = 
new CopyOnWriteArraySet<WebSocketTest>();
private Session session;
public Session getSession(){
return ;
}
@OnOpen
public void onOpen(Session session){
= session;
(this);     //加入set中
addOnlineCount();           //在线数加1
("有新连接加入!当前在线人数为" + getOnlineCount());
}
@OnClose
public void onClose(){
(this);  //从set中删除
subOnlineCount();           //在线数减1
("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 服务器向浏览器发送消息
* @param message 需要推送到浏览器的消息
* @param session 可选的参数
*/
@OnMessage
public void onMessage(String message, Session session) {
for(WebSocketTest item: webSocketSet){
try {
(message);
} catch (IOException e) {
();
continue;
}
}
}

/**
* 发生错误时调用
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error){
("发生错误");
();
}
/**
* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException{
().sendText(message);
//().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}

public static synchronized void addOnlineCount() {
++;
}

public static synchronized void subOnlineCount() {
--;
}

}

第三步:如何把自己的信息借助上面的WebSocketTest类推送出去
-----------------------------

比如服务器有一个字符串“鄂H AAAAA8”这样的字符串,要把它推到浏览器里显示出来,

其实只要三句话搞定:


String license=“鄂H AAAAA8”;

//new一个WebSocketTest对象,表示我要用它来发送
WebSocketTest wst=new WebSocketTest();
//这个session实际上是import ;
Session session=();
//调用这个webSocketTest对象的onMessage就可以把license发送出去了。
(license, session);

全文完:湖北荆门金庭波 QQ:14280784