fix: 压测客户端改为 MQTT 5 并完成 hello 与收发统计

This commit is contained in:
Nixevol
2026-09-30 16:24:31 +08:00
parent 09fb544b7d
commit c72d1f0427
11 changed files with 1398 additions and 259 deletions
+153
View File
@@ -0,0 +1,153 @@
package load
import (
"bytes"
"fmt"
"io"
"github.com/mochi-mqtt/server/v2/packets"
)
const (
mqttProtocolLevel5 = 5
mqttKeepaliveSec = 30
)
// encodeConnect 按 DEVELOPMENT §5 生成 MQTT 5 CONNECT:
// ClientID=Username=端编号、CleanStart、心跳 30、会话过期间隔缺省为 0(Clean Start 时即为 0)。
// 不声明 Receive Maximum,避免踩 mochi 发送配额路径。
func encodeConnect(endpointID, password string) ([]byte, error) {
pk := packets.Packet{
FixedHeader: packets.FixedHeader{Type: packets.Connect},
ProtocolVersion: mqttProtocolLevel5,
Connect: packets.ConnectParams{
ProtocolName: []byte("MQTT"),
Clean: true,
ClientIdentifier: endpointID,
Keepalive: mqttKeepaliveSec,
UsernameFlag: true,
Username: []byte(endpointID),
PasswordFlag: true,
Password: []byte(password),
},
}
var buf bytes.Buffer
if err := pk.ConnectEncode(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func encodeSubscribe(packetID uint16, endpointID string) ([]byte, error) {
pk := packets.Packet{
FixedHeader: packets.FixedHeader{Type: packets.Subscribe, Qos: 1},
ProtocolVersion: mqttProtocolLevel5,
PacketID: packetID,
Filters: packets.Subscriptions{
{Filter: downTopic(endpointID), Qos: 1},
},
}
var buf bytes.Buffer
if err := pk.SubscribeEncode(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func encodePublish(packetID uint16, endpointID string, payload []byte) ([]byte, error) {
pk := packets.Packet{
FixedHeader: packets.FixedHeader{Type: packets.Publish, Qos: 1},
ProtocolVersion: mqttProtocolLevel5,
TopicName: upTopic(endpointID),
PacketID: packetID,
Payload: payload,
}
var buf bytes.Buffer
if err := pk.PublishEncode(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func encodePuback(packetID uint16) ([]byte, error) {
pk := packets.Packet{
FixedHeader: packets.FixedHeader{Type: packets.Puback},
ProtocolVersion: mqttProtocolLevel5,
PacketID: packetID,
}
var buf bytes.Buffer
if err := pk.PubackEncode(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func encodePingreq() []byte {
return []byte{0xC0, 0x00}
}
func downTopic(id string) string { return "nix/c/" + id + "/down" }
func upTopic(id string) string { return "nix/c/" + id + "/up" }
func connackReason(raw []byte) (byte, error) {
if len(raw) < 2 || raw[0]>>4 != packets.Connack {
return 0, fmt.Errorf("不是 CONNACK:type=0x%02x len=%d", byteAt(raw, 0), len(raw))
}
rem, n, err := decodeRemainingLength(raw[1:])
if err != nil {
return 0, err
}
body := raw[1+n:]
if rem < 2 || len(body) < 2 {
return 0, fmt.Errorf("CONNACK 过短 remaining=%d body=%d", rem, len(body))
}
return body[1], nil
}
func decodePublish(raw []byte) (payload []byte, packetID uint16, qos byte, err error) {
if len(raw) < 2 {
return nil, 0, 0, io.ErrUnexpectedEOF
}
qos = (raw[0] >> 1) & 0x3
rem, n, err := decodeRemainingLength(raw[1:])
if err != nil {
return nil, 0, 0, err
}
body := raw[1+n:]
if len(body) != rem {
return nil, 0, 0, io.ErrUnexpectedEOF
}
pk := packets.Packet{
ProtocolVersion: mqttProtocolLevel5,
FixedHeader: packets.FixedHeader{
Type: packets.Publish,
Remaining: rem,
Qos: qos,
},
}
if err := pk.PublishDecode(body); err != nil {
return nil, 0, qos, err
}
return pk.Payload, pk.PacketID, qos, nil
}
func decodeRemainingLength(b []byte) (value int, n int, err error) {
var mul uint32 = 1
var v uint32
for i := 0; i < len(b) && i < 4; i++ {
v += uint32(b[i]&127) * mul
n++
if b[i]&128 == 0 {
return int(v), n, nil
}
mul *= 128
}
return 0, 0, io.ErrUnexpectedEOF
}
func byteAt(b []byte, i int) byte {
if i < 0 || i >= len(b) {
return 0
}
return b[i]
}