webSocket基础

一、介绍

WebSocket 是一种网络通信协议,很多高级功能都需要它。
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信
(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

ws://example.com:80/some/path

在这里插入图片描述

1.1、请求流程

WebSocket 不同于TCP的三次握手。 WebSocket是先进行一次HTTP请求,这个请求头不同于普通HTTP请求。然后服务器开始辨认请求头,如果是WebSocket的请求头,则进行普通的TCP连接,即三次握手。如果不是WebSocket的请求头,按普通的HTTP请求处理。

WebSocket请求头(Sec-WebSocket-Key)

GET ws://localhost:12345/websocket/test.html HTTP/1.1
 Origin: http://localhost
 Connection: Upgrade
 Host: localhost:12345
 Sec-WebSocket-Key: JspZdPxs9MrWCt3j6h7KdQ==  // 这个叫“梦幻字符串”,这个加密规则可以去百度。只有有这个密钥 服务器才能通过解码 认出来,哦~这是个WebSocket的请求,我要建立TCP连接了!!!如果这个字符串没有按照加密规则加密,那服务端就认不出来,就会认为这整个协议就是个HTTP请求。更不会开TCP。其他的字段都可以随便设置,但是这个字段是最重要的字段,标识WebSocket协议的一个字段。
 Upgrade: websocket 
Sec-WebSocket-Version: 13

服务器回应(Sec-WebSocket-Accept)

HTTP/1.1 101 Web Socket Protocol Handshake
 WebSocket-Location: ws://localhost:12345/websocket/test.php
 Connection: Upgrade
 Upgrade: websocket
 Sec-WebSocket-Accept: zUyzbJdkVJjhhu8KiAUCDmHtY/o= // 这个字符串是要让客户端辨认的,客户端拿到后自动解码。并且辨认是不是一个WebSocket请求。然后进行相应的操作。加密规则百度。
 WebSocket-Origin: http://localhost

ps:TCP三次握手
第一次握手,客户主动(active open)去connect服务器,并且发送SYN 假设序列号为J,服务器是被动打开(passive open);
第二次握手,服务器在收到SYN后,它会发送一个SYN以及一个ACK(应答)给客户,ACK的序列号是 J+1表示是给SYN J的应答,新发送的SYN K 序列号是K;
第三次握手,客户在收到新SYN K, ACK J+1 后,也回应ACK K+1 以表示收到了,然后两边就可以开始数据发送数据了。

二、api

1、构造函数

var ws = new WebSocket('ws://localhost:8080');

执行上面语句之后,客户端就会与服务器进行连接。
实例对象的所有属性和方法清单,参见:https://developer.mozilla.org/en-US/docs/Web/API/WebSocket

2、webSocket.readyState 返回实例对象的当前状态

CONNECTING:值为0,表示正在连接。
OPEN:值为1,表示连接成功,可以通信了。
CLOSING:值为2,表示连接正在关闭。
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

3、webSocket.onopen 指定连接成功后的回调函数

ws.onopen = function () {
  ws.send('Hello Server!');
}

//如果要指定多个回调函数,可以使用addEventListener方法。
ws.addEventListener('open', function (event) {
  ws.send('Hello Server!');
});

4、webSocket.onclose 指定连接关闭后的回调函数。同上

5、webSocket.onerror 指定报错时的回调函数。同上

6、 webSocket.onmessage 指定收到服务器数据后的回调函数。同上
注意,服务器数据可能是文本,也可能是二进制数据(blob对象或Arraybuffer对象)。

ws.onmessage = function(event){
  if(typeof event.data === String) {
    console.log("Received data string");
  }

  if(event.data instanceof ArrayBuffer){
    var buffer = event.data;
    console.log("Received arraybuffer");
  }
}

//除了动态判断收到的数据类型,也可以使用binaryType属性,显式指定收到的二进制数据类型。
// 收到的是 blob 数据
ws.binaryType = "blob";
ws.onmessage = function(e) {
  console.log(e.data.size);
};

// 收到的是 ArrayBuffer 数据
ws.binaryType = "arraybuffer";
ws.onmessage = function(e) {
  console.log(e.data.byteLength);
};

7、webSocket.send() 向服务器发送数据

//发送文本对象的例子。
ws.send('your message');

//发送 Blob 对象的例子。
var file = document
  .querySelector('input[type="file"]')
  .files[0];
ws.send(file);

//发送 ArrayBuffer 对象的例子。
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
ws.send(binary.buffer);

8、webSocket.bufferedAmount 判断发送是否结束(还有多少字节的二进制数据没有发送出去)

var data = new ArrayBuffer(10000000);
socket.send(data);

if (socket.bufferedAmount === 0) {
  // 发送完毕
} else {
  // 发送还没结束
}

标题三、简单使用

1、vue

//连接websocket
connectWebsocket(){        
	let _this = this
    let webSocket = new WebSocket(this.$httpUrl.ws)
    webSocket.onopen = () => {
	    console.log('已连接')
        webSocket.onmessage = e => {
	        let content = JSON.parse(e.data)
            console.log(content)
        }
    }
    webSocket.onclose = () => {
	    let _timer = setTimeout(()=>{
	        console.log('正在重新连接')
            _this.connectWebsocket()
            clearTimeout(_timer)
        }, 2000)
   }
    webSocket.onerror = () => {
	    console.log('网络不畅通,请联系管理员')
    }
}

全局websocket

//main.js
Vue.prototype.ws = new WebSocket(Httpurl.ws)

//app.vue
webSk() {
	let that = this;
    // let webSocket = new WebSocket(this.$httpApi.ws);
    this.ws.onopen = () => {
	    console.log("已连接");
          // this.ws.onmessage = e => {
          //   let obj = JSON.parse(e.data);
          //   console.log(obj);
          // }
    };
    this.ws.onclose = () => {
	    console.log('已关闭连接');
        let _timer = setTimeout(()=>{
        console.log('正在重新连接')
        that.webSk()
        clearTimeout(_timer)
          }, 2000)
    };
    this.ws.onerror = () => {
       console.log("网络不畅通,请联系管理员");
    };
},

//任意页面
let data={
	key:'Compute_Range',
	data:{
		startTime: that.trackForm.startTime,
    	endTime: that.trackForm.endTime
	}
}
this.ws.send(JSON.stringify(data))

2、uni-app

webSk() {
	let that = this;
	let socketTask = uni.connectSocket({
		url: this.$lyApi.ws, //仅为示例,并非真实接口地址。
		header: {
			'content-type': 'application/json'
		},
		method: 'GET',
		success: ()=> {}
	});
	socketTask.onOpen(function(){
		console.log('连接已打开');
		socketTask.onMessage(function(res){
			let obj = JSON.parse(res.data);
		}
	})
	socketTask.onClose(function(){
		console.log('连接已关闭');
		let _timer = setTimeout(()=>{
	        console.log('正在重新连接')
            that.webSk()
            clearTimeout(_timer)
        }, 2000)
	})
	socketTask.onError(function(){
		that.$common.errorToShow('网络不畅通,请联系管理员');
	})
},

四、心跳包

在实际项目中,别让这种长连接一直保持,可以设置连接无交流超时断开,大概设置10分钟左右,然后每8分钟定时发送一条心跳,具体想法就看你们喽~

webSk() {
      let that = this;
      let webSocket = null; 
      let heartFlag = false; // webSocket连接成功标识
      let tryTime = 0; // 尝试连接次数
      initWs();

      // 心跳函数,每8分钟执行一次
      function heart(){
        heartFlag && webSocket.send("keep connection"); // 发送一条心跳
        const timer = setTimeout(() => {
          heart();
          clearTimeout(timer);
        }, 8 * 60 * 1000);
      }

      function initWs(){
        webSocket = new WebSocket(that.$httpUrl.lotteryws);

        webSocket.onopen = () => {
          console.log('websocket连接成功')
          heartFlag = true
          tryTime = 0 // 连接成功,尝试次数设为0
          heart()
        }

        // 接收信息
        webSocket.onmessage = function(e) {
          let obj = JSON.parse(e.data);
          console.log("obj",obj)
        };

        // 连接关闭
        webSocket.onclose = () => {
          console.log('websocket已关闭连接');
          heartFlag = false;
          if(tryTime < 10){ // 连接关闭尝试重新连接,尝试超过10次提示错误。
            const _timer = setTimeout(() => {
              window.console.log('websocket正在重新连接');
              webSocket = null;
              tryTime++;
              initWs();
              clearTimeout(_timer)
            }, 2000)
          }else{
            window.console.log('websocket重连失败,请刷新页面重试')
          }
        };

        // 连接错误
        webSocket.onerror = () => heartFlag = false
      }
    },

五、待求证
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值