websocket算法

websocket协议中的一些算法

在分析 WebSocket 协议握手过程和数据帧格式过程中,我们讲到了一些算法,下面我们讲解下具体实现。

Sec-WebSocket-Accept的计算方法

从上面的分析中,我们知道字段的值是通过固定字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11加上请求中Sec-WebSocket-Key字段的值,然后再对其结果通过 SHA1 哈希算法求出的结果。可以通过以下 golang 代码实现:

1
2
3
4
5
6
7
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
func computeAcceptKey(challengeKey string) string {
h := sha1.New()
h.Write([]byte(challengeKey))
h.Write(keyGUID)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

掩码处理

浏览器发送给服务器的数据帧是经过掩码处理的,那怎么样对数据进行解码呢?以下是来自RFC6455文档的解释

具体的流程是:将传输的数据按字节 byte 处理,同时将 Masking-key 代表的值也按字节处理。假如 data-byte-i 代表的是数据的第 i 个字节,那么 j = i MOD 4,然后从Maksing-key中(一共有 4 个字节)取出第 j 个字节 mask-key-byte-j,然后将 data-byte-imask-key-byte-j 代表的字节进行异或操作,取得结果就是最终的结果。该操作可以用如下 golang 代码实现:

1
2
3
4
5
6
7
func maskBytes(key [4]byte,pos int,b[]byte)int{
for i := range b{
b[i] ^= key[pos & 3]
pos++
}
return pos & 3
}

注意以上的操作,pos & 3这里代表的操作是pos%4,因为 a % (2 ^ n) 等价于 a & (2^n -1),在这里使用按位与操作更加高效