有奖捉虫:行业应用 & 管理与支持文档专题 HOT

基本概念

Socket.IO

Socket.IO 是一个面向 Web 端即时通信技术的代码工具库,它主要基于 WebSocket 协议建立连接,同时也把 HTTP 长轮询 作为后备方案,支持即时、双向、基于事件的通信。其主要特性如下:
高性能:在大多数情况下,它使用 WebSocket 协议建立连接,在客户端和服务器之间,提供双向、低延迟的通信通道。
可靠性:在无法建立 WebSocket 连接时(例如浏览器不支持 WebSocket 协议、或 WebSocket 连接被代理或防火墙拦截等),它将使用 HTTP 长轮询作为替代方案。另外,如果连接丢失,客户端将自动重试连接。
可扩展:支持将应用程序部署到多个服务器,向所有连接的客户端发送事件。

WebSocket

WebSocket 是一种应用层通信协议,可在单个 TCP 连接上进行全双工通信。
不同于 HTTP 协议的客户端发起请求、服务端响应的一问一答模式,WebSocket 连接一旦建立,直到连接关闭之前,客户端、服务器之间都可源源不断地、双向地交换数据。

HTTP 长轮询

HTTP 长轮询是一种基于 HTTP 协议的 Web 端即时通信技术。当服务器收到客户端发来的请求后,不会直接进行响应,而是先将这个请求挂起,判断服务器端数据是否有更新:
如果有数据更新,则服务器正常返回响应。
如果一直没有数据更新,则达到服务器端设置的超时时间后返回。
客户端则会在处理完服务器返回的响应后,再次发出请求,重新建立连接。
HTTP 长轮询和 HTTP 短轮询相比较,HTTP 长轮询在无数据更新的情况下,不会频繁发送请求,减少了不必要的请求次数、节约了资源。

Socket.IO 压测介绍

在 PTS 压测场景中,基于 Socket.IO 请求的脚本与基于 HTTP 请求的脚本,其结构和作用机制有所不同:
执行 HTTP 脚本的每个 VU 会持续不断地迭代主函数 (export default function() { ... }),直到压测结束。
执行 Socket.IO 脚本的每个 VU 不会持续迭代主函数,因为主函数会被建立连接的 io.connect 方法阻塞,直到连接关闭。而在连接建立后的回调函数里(function (socket) {...}),会持续不断地监听和处理异步事件,直到压测结束。

脚本编写

PTS API 的 Socket.IO 模块提供了 Socket.IO 协议的相关接口,详情可参见 socketio API。 使用这些接口,您可以建立 Socket.IO 连接、发送/收取事件消息。
基本用法:
connect 方法建立连接,并在其回调函数里定义您的业务逻辑:
该方法的必传参数为待连接服务的 URL,和连接成功后需执行的回调函数。
该方法的可选参数为调整配置的选项,包括:
protocol:协议类型,支持 polling(HTTP 长轮询)和 websocket(WebSocket)。
headers:请求头参数。
若连接建立成功,PTS 会将创建好的SocketIO对象传入回调函数。您可在回调函数里,定义您的 Socket.IO 请求逻辑,发送/收取事件消息。
执行完回调函数,connect 会返回 Response 对象,200 为成功返回码。
SocketIO 对象的常用方法:
emit:发送事件。参数为事件名、消息数据、回调函数:
event:自定义事件的名称。
msg:文本消息或二进制数据。
callback: (可选)回调函数。
close:关闭连接。
on:监听事件,并用回调函数处理事件。PTS 支持监听的事件列表如下:
事件名
事件用途
open
建立连接
close
关闭连接
error
发生错误
message
接收文本消息
binaryMessage
接收二进制消息
setTimeout: 等待 intervalMs 毫秒后执行函数。
setInterval:按照 intervalMs 毫秒定期执行函数。
setLoop:循环执行函数直至 context 结束或者连接关闭。
代码示例如下:
// SocketIO API
import socketio from 'pts/socketio';
import { check, sleep } from 'pts';
import util from 'pts/util';

export default function () {
const res = socketio.connect('http://localhost:8080', function (socket) {
socket.on('open', () => console.log('connected'));
socket.on('message', (data) => console.log('message received: ', data));
socket.on('binaryMessage', (data) => console.log('binaryMessage received: ', data));
socket.on('close', () => console.log('disconnected'));
socket.setTimeout(function () {
console.log('3 seconds passed, closing the socket');
socket.close();
}, 3000);
// 设置定时任务
socket.setTimeout(function () {
socket.emit('message', 'hello');
socket.emit('binaryMessage', util.base64Decoding('aGVsbG8=', 'std', 'b'));
socket.emit('ackMessage', 'hello ack', function(msg) {
console.log('ack message received: ', msg)
})
}, 500);
// 设置定期执行的任务
socket.setInterval(function(){
socket.emit('message', 'interval message');
}, 500);
// 设置循环执行任务,socket/context 关闭自然退出
socket.setLoop(function () {
sleep(0.1);
socket.emit('message', 'loop message');
});
}, {
// 支持 polling、websocket 协议
protocol:'websocket',
headers: {
token: 'xxx',
}
});
check('status is 200', () => res.status === 200);
}

脚本验证

若要验证脚本执行结果,可在正式压测前,先使用 PTS 调试功能,快速验证结果是否符合预期。更多详情可参见 调试场景

文件依赖

在压测场景里,您可上传以下几种类型的文件,提供压测执行时的状态数据:
参数文件:以 csv 文件的形式,动态提供测试数据。也即,场景被每个并发用户(VU)执行时,会获取参数文件里的每行数据,作为测试数据的值,供脚本里的变量引用。具体使用方法参见:使用参数文件
请求文件:构建您的请求所需的文件,如需要上传的文件。具体使用方法参见:使用请求文件
协议文件:请求序列化所需要用到的文件。具体使用方法参见:使用协议文件