websocket学习笔记

websocket学习笔记

WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

为什么需要 WebSocket ?
初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?
答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起。
举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。
轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。

随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。

我们知道,传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应用。

实现的方式

//先握手,并查看客户端的浏览器是否支持websocket协议
//连接发生错误的回调方法
ws.onerror = function () {
    alert("WebSocket连接发生错误");
};

//连接成功建立的回调方法
ws.onopen = function () {
    alert("WebSocket连接成功");
}

//接收到消息的回调方法,websocket的controller里的onMessage方法session_to传过来的值
ws.onmessage = function (event) {
    alert(event.data);
}
 
//连接关闭的回调方法
ws.onclose = function () {
    alert("WebSocket连接关闭");
}
    
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
    closeWebSocket();
}

function closeWebSocket(){
	ws.close();
}

在这里插入图片描述
nodejs实现websocket:

let ws = require('ws');            //引入websocket模块
let uuid = require('uuid');        //引入创建唯一id模块
let socketServer = ws.Server;
let clientIndex = 0;
let wss = new socketServer({port: 8090}, ()=>{
	console.log("服务启动,端口8090.")
});    //创建websocketServer实例监听8090端口

let clients = [];                //创建客户端列表,用于保存客户端及相关连接信息

/**
 * 广播所有客户端消息
 * @param  {String} type     广播方式(admin为系统消息,user为用户消息)
 * @param  {String} message  消息
 * @param  {String} nickname 用户昵称,广播方式为admin时可以不存在
 */
function broadcastSend(type, message, nickname) {
	console.log("type:"+type)
    clients.forEach(function(v, i) {
        if(v.ws.readyState === ws.OPEN) {
            v.ws.send(JSON.stringify({
                "type": type,
                "nickname": nickname,
                "message": message
            }));
        }
    })
}

//定时发送图表数据
function echartData() {
    function sortNumber(a,b){
        return a-b;//升序
    }
    //测试数据
    var iArray = [];
    function getRamdon(start, end) {
        var temp = end - start + 1;   //91
        return Math.abs(Math.floor(Math.random()*temp)) + start;   //从start开始
    }
    for(var i=0; i < 10; i++) {
        iArray.push(getRamdon(100,1000))   //循环10次,添加10个数在数组里
    }
    iArray.sort(sortNumber);
    return iArray;
}

var inter = null;
function echartSend() {
	//第一次,以后每5秒更新一次
	var arr = echartData();
	broadcastSend("echart", arr, "system");
	if (inter) clearInterval(inter);
    inter = setInterval(function() {
        var arr = echartData();
        broadcastSend("echart", arr, "system");
    }, 5000)
}

//监听连接
wss.on('connection', function(ws) {
    let client_uuid = uuid.v4();
    let nickname = `AnonymousUser${clientIndex++}`;
    clients.push({
        "id": client_uuid,
        "ws": ws,
        "nickname": nickname
    });
    //发送图表数据
    echartSend();
    console.log(`client ${client_uuid} connected`);
    /**
     * 关闭服务,从客户端监听列表删除
     */
    function closeSocket() {
        for(let i = 0; i < clients.length; i++) {
          if(clients[i].id == client_uuid) {
            let disconnect_message = `${nickname} has disconnected`;
            broadcastSend("notification", disconnect_message, nickname);
            clients.splice(i, 1);
          }
        }
		//无客户端时停止定时器
		if (clients.length == 0){
			console.log("无客户端连接,清除定时器。")
			if (inter) clearInterval(inter);
		}
    }
    /*监听消息*/
    ws.on('message', function(message) {
        if(message.indexOf('/nick') === 0) {
            let nickname_array = message.split('_');
            if(nickname_array.length >= 2) {
                let old_nickname = nickname;
                nickname = nickname_array[1];
                let nickname_message = `Client ${old_nickname} change to ${nickname}`;
                broadcastSend("nick_update", nickname_message, nickname);
            }
        } else {
            broadcastSend("message", message, nickname);
        }
    });
    /*监听断开连接*/
    ws.on('close', function() {
        closeSocket();
    })
})

【其他代码可参考】https://gitee.com/monkeyhlj/vue-learning/tree/master/20210809-WebSocket%E5%AD%A6%E4%B9%A0
【Java实现可参考】Java实现websocket

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值