k6系列之websocket实战--在线协同文档的自动化以及压测

认识协同文档的报文

  • 报文录制
    1
    2
    Copy-copy all as har
    find: _webSocketMessages
  • 报文分析
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    0200 086e 6f20 746f 6b65 6e              ...no token
    base64编译:AgAIbm8gdG9rZW4=
    对照ASCII表
    这里是十六进制,02代表ASCII中的STX (Start Of Text) 00则是NULL, 6e是n,对应最后一个字母n,诸如此。
    如果从base64转换成arrybuff,那么则对应二进制的值,比如n对应01101110,在js中打印显示为十进制110
    var buff = encoding.b64decode(base64String, 'std')
    let uint8View = new Uint8Array(buff);


    const uint8Array = new Uint8Array(3); // 创建一个长度为3的Uint8Array

    // 使用十进制值来修改数组中的元素
    uint8Array[0] = 42; // 将第一个元素的值设置为十进制的42
    uint8Array[1] = 128; // 将第二个元素的值设置为十进制的128
    uint8Array[2] = 255; // 将第三个元素的值设置为十进制的255

    // 打印修改后的数组内容
    console.log(uint8Array); // 打印数组

    单人模式下协同文档的自动化压测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const ws = new WebSocket(url, null, params1);

ws.addEventListener('open', () => {
//这里要用==1来比较,因为readyState的类型是ReadyState,要用非严格比较
if (!check(ws, {
'is status 200': (r) => r.readyState == 1,
})){
ws.close()
}
//case 1 2分别对应报文中opcode的类型,如text binary
for (const mess of messages){
switch(mess.opcode){
case 1:
//省略
break;
case 2:
//省略
break;
default:
//省略
}
}
// listen for messages/errors and log them into console
ws.addEventListener('message', (e) => {
console.log(e, "###")
});
ws.addEventListener('close', () => {
console.log(`VU ${__VU} disconnected`);
});
ws.close()
});

在 WebSocket (ws) 协议中,”opcode” 表示控制帧或数据帧的类型。它指示 WebSocket 数据帧的类型和如何处理这些帧。WebSocket 数据帧可以是控制帧或数据帧,而 “opcode” 字段用于标识这些帧的类型。

具体来说,”opcode” 字段的值指示了数据帧的用途。其中一些常见的 “opcode” 值包括:

  • 0x0(十进制为 0): 表示一个继续帧。当消息需要分片发送时,后续的分片消息会使用此类型。
  • 0x1(十进制为 1): 表示一个文本帧。用于传输文本消息。
  • 0x2(十进制为 2): 表示一个二进制帧。用于传输二进制数据。
  • 0x8(十进制为 8): 表示一个连接关闭帧。表示连接被关闭。
  • 0x9(十进制为 9): 表示一个 ping 帧。用于检查连接是否仍然存活。
  • 0xA(十进制为 10): 表示一个 pong 帧。对 ping 帧的响应。

UTF-8 编码原理

ASCII 字符: 0x00 - 0x7F(0 - 127)范围内的字符(包括常见的英文字母、数字和标点符号),使用一个字节编码。
扩展的拉丁字符: 0x80 - 0x7FF(128 - 2047)范围内的字符,使用两个字节编码。
BMP 平面字符: 0x800 - 0xFFFF(2048 - 65535)范围内的字符,包括大多数的汉字,使用三个字节编码。
辅助平面字符: 0x10000 - 0x10FFFF(65536 - 1114111)范围内的字符,使用四个字节编码。
中文字符在 UTF-8 中的编码
一个中文字符的 Unicode 码点通常在 0x4E00 - 0x9FFF(即 19968 - 40959)范围内。根据 UTF-8 编码规则,这些字符会被编码成三个字节。

例如,“你”字的 Unicode 码点是 0x4F60。

将 0x4F60 转换成二进制: 01001111 01100000
UTF-8 编码规则(3字节)
UTF-8 三字节编码的格式如下:

第一个字节:1110xxxx
第二个字节:10xxxxxx
第三个字节:10xxxxxx
拆分代码点
将二进制的 0x4F60 (0100 1111 0110 0000) 按照 UTF-8 的三字节格式进行拆分:

原始的 16 位二进制:0100 1111 0110 0000

从右往左填充 xxxxxx 的位置:

第一个字节:1110xxxx -> 11100100
第二个字节:10xxxxxx -> 10111101
第三个字节:10xxxxxx -> 10100000
我们将 0100 1111 0110 0000 填入这三个字节的 x 位置中:

第一个字节:1110 0100
第二个字节:1011 1101
第三个字节:1010 0000
转换为十六进制
将这三个字节(每个字节 8 位)的二进制转换为十六进制:

1110 0100 = 0xE4
1011 1101 = 0xBD
1010 0000 = 0xA0
UTF-8 编码结果
因此,Unicode 代码点 0x4F60 在 UTF-8 中的编码是 E4 BD A0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 将字符串转换为 Uint8Array
function stringToUint8Array(str) {
let arr = new Uint8Array(str.length);
for (let i = 0; i < str.length; i++) {
arr[i] = str.charCodeAt(i);
}
return arr;
}
// 替换字节序列
function replaceSequence(array, targetSequence, replacementSequence) {
const strArray = array.join(',');
const strTarget = targetSequence.join(',');
const strReplacement = replacementSequence.join(',');

if (strArray.includes(strTarget)) {
const strNewArray = strArray.replace(strTarget, strReplacement);
return new Uint8Array(strNewArray.split(',').map(Number)).buffer;
} else {
return array.buffer;
}
}
function customModifiArrBuff(base64String, oldstring, newstringdata){
// 原始 Uint8Array
var oldbuff = encoding.b64decode(base64String, 'std')
let originalArray = new Uint8Array(oldbuff);

// 要查找的字节序列
let targetSequence = stringToUint8Array(oldstring);

// 替换的字节序列
let replacementSequence = stringToUint8Array(newstringdata);;

// 执行替换
let newArray = replaceSequence(originalArray, targetSequence, replacementSequence);
return newArray

}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!