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() {

ws.onclose = function () {

console.info("连接关闭");

reconnect(wsUrl);

};

ws.onerror = function () {

console.info("传输异常");

reconnect(wsUrl);

};

ws.onopen = function () {

//心跳检测重置

heartCheck.reset().start();

};

websocket.onmessage = function(event) {

//console.info(event.data);

setMessageInnerHTML(event.data);

//如果获取到消息,心跳检测重置

heartCheck.reset().start();

}

}

function reconnect(url) {

if(lockReconnect) return;

lockReconnect = true;

//没连接上会一直重连,设置延迟避免请求过多

setTimeout(function () {

console.info("尝试重连..." + 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(this.timeoutObj);

clearTimeout(this.serverTimeoutObj);

return this;

},

start: function(){

var self = this;

this.timeoutObj = setTimeout(function(){

//这里发送一个心跳,后端收到后,返回一个心跳消息,

//onmessage拿到返回的心跳就说明连接正常

ws.send("HeartBeat" + new Date().format("yyyy-MM-dd hh:mm:ss"));

console.info("客户端发送心跳:" + new Date().format("yyyy-MM-dd hh:mm:ss"));

self.serverTimeoutObj = setTimeout(function(){

//如果超过一定时间还没重置,说明后端主动断开了

ws.close();

//如果onclose会执行reconnect,我们执行ws.close()就行了.

//如果直接执行reconnect 会触发onclose导致重连两次

}, self.timeout)

}, this.timeout)

}

}

//js中格式化日期,调用的时候直接:new Date().format("yyyy-MM-dd hh:mm:ss")

Date.prototype.format = function(fmt) {

var o = {

"M+" : this.getMonth()+1, //月份

"d+" : this.getDate(), //日

"h+" : this.getHours(), //小时

"m+" : this.getMinutes(), //分

"s+" : this.getSeconds(), //秒

"q+" : Math.floor((this.getMonth()+3)/3), //季度

"S" : this.getMilliseconds() //毫秒

};

if(/(y+)/.test(fmt)) {

fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));

}

for(var k in o) {

if(new RegExp("("+ k +")").test(fmt)){

fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));

}

}

return fmt;

}

function setMessageInnerHTML(innerHTML) {

document.getElementById('message').innerHTML += innerHTML + '<br/>';

}

</script>

第二步:在java的controller包中写一个WebSocketTest类

------------------------------

package com.clmarket.controller;

import javax.websocket.*;

import javax.websocket.server.ServerEndpoint;

import java.io.IOException;

import java.util.concurrent.CopyOnWriteArraySet;

@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 this.session;

}

@OnOpen

public void onOpen(Session session){

this.session = session;

webSocketSet.add(this); //加入set中

addOnlineCount(); //在线数加1

System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());

}

@OnClose

public void onClose(){

webSocketSet.remove(this); //从set中删除

subOnlineCount(); //在线数减1

System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());

}

/**

* 服务器向浏览器发送消息

* @param message 需要推送到浏览器的消息

* @param session 可选的参数

*/

@OnMessage

public void onMessage(String message, Session session) {

for(WebSocketTest item: webSocketSet){

try {

item.sendMessage(message);

} catch (IOException e) {

e.printStackTrace();

continue;

}

}

}

/**

* 发生错误时调用

* @param session

* @param error

*/

@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);

//this.session.getAsyncRemote().sendText(message);

}

public static synchronized int getOnlineCount() {

return onlineCount;

}

public static synchronized void addOnlineCount() {

WebSocketTest.onlineCount++;

}

public static synchronized void subOnlineCount() {

WebSocketTest.onlineCount--;

}

}

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

-----------------------------

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

其实只要三句话搞定:

String license=“鄂H AAAAA8”;

//new一个WebSocketTest对象,表示我要用它来发送

WebSocketTest wst=new WebSocketTest();

//这个session实际上是import javax.websocket.Session;

Session session=wst.getSession();

//调用这个webSocketTest对象的onMessage就可以把license发送出去了。

wst.onMessage(license, session);

-

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

相关推荐