fix: 压测客户端改为 MQTT 5 并完成 hello 与收发统计
This commit is contained in:
@@ -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]
|
||||
}
|
||||
Reference in New Issue
Block a user