首页 > 其他分享 >WebSocket 协议 message, ping , Pong, 消息

WebSocket 协议 message, ping , Pong, 消息

时间:2024-02-05 14:47:18浏览次数:37  
标签:WebSocket 字节 ping 掩码 message 数据 bit 服务端 客户端

以前一直不明白,WebSocket  已经有了 message 回调函数,可以接收任何的消息, 按理说,ping 和 pong 也只是  message  众多消息类型中的两个消息特里,直到看到  <<WebSocket 协议 >> 的定义,才明白,为什么了

 

一、数据帧(Data Framing)

WebSocket协议中,数据是通过数据帧来传递的,协议规定了数据帧的格式,服务端要想给客户端推送数据,必须将要推送的数据组装成一个数据帧,这样客户端才能接收到正确的数据;同样,服务端接收到客户端发送的数据时,必须按照帧的格式来解包,才能真确获取客户端发来的数据。

RFC文档中对帧的格式定义如下所示:
in ord to achievethat above mentioned design,

乍一看乱七八糟的,看这种东西尤其对前端同学来说,特别晦涩,看到这个东西很容易联想到,大学计算机网络中讲到的TCP/IP协议报文格式,毕竟咱也是科班出身的,下面听我细细道来。

最上方的第二排数字,每个数字表示一个bit位,这个可以用来确定数据帧格式的每一部分占用的bit位数。

1. FIN1.翅片

1个bit位,用来标记当前数据帧是不是最后一个数据帧,因为一个消息可能会分成多个数据帧来传递,当然,如果只需要一个数据帧的话,第一个数据帧也就是最后一个。

2. RSV1, RSV2, RSV32. RSV 1,RSV 2,RSV 3

这三个,各占用一个bit位,根据RFC的介绍,这三个bit位是用做扩展用途,没有这个需求的话设置位0。

3. Opcode3.操作码

故名思议,操作码,占用4个bit位,也就是一个16进制数,它用来描述要传递的数据是什么或者用来干嘛的,只能为下面这些值:

0x0 denotes a continuation frame 标示当前数据帧为分片的数据帧,也就是当一个消息需要分成多个数据帧来传送的时候,需要将opcode设置位0x0。

0x1 denotes a text frame 标示当前数据帧传递的内容是文本

0x2 denotes a binary frame 标示当前数据帧传递的是二进制内容,不要转换成字符串

0x8 denotes a connection close 标示请求关闭连接

0x9 denotes a ping 标示Ping请求0x9表示ping标记表示Ping请求

0xA denotes a pong 标示Pong数据包,当收到Ping请求时自动给回一个Pong

目前协议中就规定了这么多,0x30x7以及0xB0xF都是预留作为其它用途的。

4. MASK4.掩模

占用一个bit位,标示数据有没有使用掩码,RFC中有说明,服务端发送给客户端的数据帧不能使用掩码,客户端发送给服务端的数据帧必须使用掩码。

如果一个帧的数据使用了掩码,那么在Maksing-key部分必须是一个32个bit位的掩码,用来给服务端解码数据。

5. Payload len5.有效载荷透镜

数据的长度,默认位7个bit位。

如果数据的长度小于125个字节(注意:是字节)则用默认的7个bit来标示数据的长度。

如果数据的长度为126个字节,则用后面相邻的2个字节来保存一个16bit位的无符号整数作为数据的长度。

如果数据的长度大于126个字节,则用后面相邻的8个字节来保存一个64bit位的无符号整数作为数据的长度。

6. Masking-key6.掩蔽键

数据掩码,如果MASK设置位0,则该部分可以省略,如果MASK设置位1,怎Masking-key位一个32位的掩码。用来解码客户端发送给服务端的数据帧。

7. Payload data7.有效载荷数据

该部分,也是最后一部分,是帧真正要发送的数据,可以是任意长度。

二、组装数据帧

明白了数据帧的格式以及各个部分的意义后,我们就可以来实际组装一个数据帧了。

具体的代码参考次碳酸钴同学的代码,大部分是移位操作和二进制的加法、与运算,只要记得代码里写的一个10进制的数字是一个字节,会占用8个bit位,一个16进制的数是4个bit位,然后结合上面对帧格式的解释,仔细看下代码应该是很好理解的,如果有什么疑问可以留言:

 

function encodeDataFrame(e){
     var s = [],
         o = new Buffer(e.PayloadData),
         l = o.length;
     //输入第一个字节
     s.push((e.FIN&lt;&lt;7)+e.Opcode);
     //输入第二个字节,判断它的长度并放入相应的后续长度消息
     //永远不使用掩码
     if(l < 126)
         s.push(l);
     else if(l < 0x10000)
         s.push(126,(l&0xFF00)>>8,l&0xFF);
     else 
        s.push(
            127, // 01111111
            0,0,0,0, //8字节数据,前4字节一般没用留空
            (l&0xFF000000)>>24,
            (l&0xFF0000)>>16,
            (l&0xFF00)>>8,
            l&0xFF
        );
     //返回头部分和数据部分的合并缓冲区
     return Buffer.concat([new Buffer(s),o]);
};

 

三、推送数据

数据帧组装完成后,我们就可以将这个帧通过建立好的TCP连接发送给客户端(浏览器)了,如下代码简单演示了,实时将服务器时间以及客户端在线时间实时推送给浏览器,并展示到页面上。

注意喽:

//timer,clients是全局变量
//服务端代码添加如下函数
function startPushData() {
    var data,
        startTime = Date.now();
    if (timer || clients.length === 0) return;
    timer = setInterval(function() {
    clients.forEach(function(client) {
            data = {
                startTime: client.startTime,
                currentTime: Date.now()
            };
            client.socket.write(encodeDataFrame({
                FIN: 1,
                Opcode: 1,
                PayloadData: JSON.stringify(data)
            }));
        });
    }, 100);
}

//在每次握手成功后添加如下代码
clients.push({
    startTime: Date.now(),
    socket: socket
});
startPushData();

 

平常我们写代码,并没有这些操作,那是因为我们一般用第三方库,别人帮我们封装了这些细节了。。。。。。。

 

 

 

标签:WebSocket,字节,ping,掩码,message,数据,bit,服务端,客户端
From: https://www.cnblogs.com/porter/p/18007941

相关文章

  • PostMessage与SendMessage区别
     PostMessage发送的消息是发送到应用程序的消息队列里,看d箭头SendMessage发送的消息是直接发送到应用程序的消息处理函数中    ......
  • Teamcenter AWC开发:调用SOA时,报错No SOA service for Bom-2008-06-StructureManagemen
    1、报错:2、分析:我一直在纠结,究竟是SOA接口报错。还是没有这个SOA接口服务。因为在AWC生成的SOA文档,是有这个接口和服务的。后来明白了。如果是SOA接口报错。在网络中看到这个接口是有响应的。也就是有返回的。 但是NoSOAservice报错,网络中,看到接口时没有返回的。 3......
  • Hello 2024C. Grouping Increases(贪心)
    我们只需要记录每个数结尾的数是多少(有点最长上升子序列的味道)这种子序列的题目很多都是这样的,因为不需要连续很多时候我们只记录最后一个元素是多少。\(记s为较大子序列结尾当前的数,t为较小子序列结尾的数,下面分类讨论\)\(当a[i]<=t<s时\)我们将a[i]既可以放进t所在的子序列,......
  • 学习unigui unidbgrid的GridsGroupingSorting【18】
    折腾一天,你不按照demo里的代码来,就是没有效果。procedureTUniGridsGroupingSorting.UniDBGrid1MultiColumnSort(Columns:TUniDBGridColumnArr;Directions:TUniSortDirections);varOrderStr:string;I:Integer;beginUniMainModule.ADOQuery5.Close;//必须在......
  • CF1919 C. Grouping Increases
    给定一个长为\(n\)的序列\(a\),你需要将该序列恰好分成两个子序列\(s,t\)。定义一个长为\(m\)的序列\(b\)的代价为\(\displaystylep(b)=\sum_{i=1}^{m-1}[b_i<b_{i+1}]\),求\(p(s)+p(t)\)的最小值。每个测试点\(t\)组测试用例。思路贪心。可以发现答案的贡献只与......
  • Applescript成功实现imessage数据筛选,imessage蓝号检测,无痕检测手机号是否注册imess
    一、imessages数据检测的两种方式:1.人工筛选,将要验证的号码输出到文件中,以逗号分隔。再将文件中的号码粘贴到iMessage客户端的地址栏,iMessage客户端会自动逐个检验该号码是否为iMessage账号,检验速度视网速而定。红色表示不是iMessage账号,蓝色表示iMessage账号。2.编写苹果MacO......
  • iMessage蓝号检测,苹果iMessages短信,iMessages群发,iMessages推信,完美实现总结 - 电
    一、PC电脑版苹果系统(MacOS)上实现imessages群发总结为以下几种方式:/*MacOS苹果系统,正常情况下,只能安装到苹果公司自己出品的Mac电脑,俗称白苹果,不能安装到各种组装机或者其他品牌的品牌机上,黑苹果的的原理,就是通过一些“破解补丁”工具欺骗macOS系统,让苹果系统认为你的电......
  • 在RunnerGo测试平台中做WebSocket、Dubbo、TCP/IP接口测试
    大家好,RunnerGo作为一款一站式测试平台不断为用户提供更好的使用体验,最近得知RunnerGo新增对,WebSocket、Dubbo、TCP/IP,三种协议API的测试支持,本篇文章跟大家分享一下使用方法。WebSocket协议WebSocket是一种在单个TCP连接上进行全双工通信的API技术。相比于传统的HTTP请求,We......
  • 在RunnerGo测试平台中做WebSocket、Dubbo、TCP/IP接口测试
    大家好,RunnerGo作为一款一站式测试平台不断为用户提供更好的使用体验,最近得知RunnerGo新增对,WebSocket、Dubbo、TCP/IP,三种协议API的测试支持,本篇文章跟大家分享一下使用方法。WebSocket协议WebSocket是一种在单个TCP连接上进行全双工通信的API技术。相比于传统的HTTP请......
  • 使用Golang实现ping检测主机在线的功能
    使用"github.com/go-ping/ping"这个第三方库可以非常简单的实现ping功能packagemainimport("fmt""os""time""github.com/go-ping/ping")funcCheckHostOnline(ipaddrstring)bool{pinger,err:=ping.N......