iOS平台SocketRocket库MQTT over WebSocket主题订阅方法咨询
Hey there! Let's figure out how to subscribe to MQTT topics using SocketRocket.
First off, it’s key to understand that SocketRocket is just a low-level WebSocket client—it doesn’t wrap MQTT protocol logic for you. MQTT over WebSocket works by sending MQTT’s binary protocol packets over the established WebSocket connection, so you’ll need to manually construct those packets yourself.
Here’s a step-by-step solution:
1. Build the MQTT Subscribe Packet
MQTT has a specific binary format for subscription requests. Below is a helper function to construct a valid MQTT 3.1.1 subscribe packet (adjust if you’re using MQTT 5.0):
func buildMQTTSubscribePacket(topic: String, qos: UInt8 = 0) -> Data { var packet = Data() // Fixed header: Subscribe packet type (0x82) with default flags let fixedHeader: UInt8 = 0x82 packet.append(fixedHeader) // Variable header: Packet ID (use a unique value for each request) let packetId: UInt16 = 1 packet.append(UInt8(packetId >> 8)) // High byte packet.append(UInt8(packetId & 0xFF)) // Low byte // Payload: Topic name + QoS level let topicData = topic.data(using: .utf8)! let topicLength = UInt16(topicData.count) // Append topic length (2 bytes) packet.append(UInt8(topicLength >> 8)) packet.append(UInt8(topicLength & 0xFF)) // Append topic data packet.append(topicData) // Append QoS level (1 byte) packet.append(qos) // Calculate and insert remaining length (MQTT's special encoding) var remainingLength = packet.count - 1 // Subtract fixed header byte var remainingLengthBytes = Data() repeat { var byte = UInt8(remainingLength % 128) remainingLength /= 128 if remainingLength > 0 { byte |= 0x80 } remainingLengthBytes.append(byte) } while remainingLength > 0 // Insert remaining length right after the fixed header packet.insert(contentsOf: remainingLengthBytes, at: 1) return packet }
2. Send the Subscribe Packet
Once your WebSocket connection is open, use SocketRocket to send the constructed packet:
func webSocketDidOpen(_ webSocket: SRWebSocket!) { print("SRWebSocket webSocketDidOpen") // Customize your topic and QoS level here let subscribePacket = buildMQTTSubscribePacket(topic: "your/target/topic", qos: 0) webSocket.send(subscribePacket) }
3. Handle MQTT Responses and Messages
You’ll need to parse incoming MQTT packets to confirm subscriptions and receive messages. Add this to your SRWebSocketDelegate:
func webSocket(_ webSocket: SRWebSocket!, didReceiveMessage message: Any!) { guard let mqttData = message as? Data else { print("Received non-binary MQTT message") return } parseMQTTPacket(data: mqttData) } private func parseMQTTPacket(data: Data) { let packetType = (data[0] & 0xF0) >> 4 switch packetType { case 0x09: // SUBACK: Subscription acknowledgment let packetId = UInt16(data[2]) << 8 | UInt16(data[3]) let grantedQoS = data[4] print("Subscribed successfully! Packet ID: \(packetId), Granted QoS: \(grantedQoS)") case 0x03: // PUBLISH: Incoming message from broker // Parse topic let topicLength = UInt16(data[2]) << 8 | UInt16(data[3]) let topicRange = 4..<4+Int(topicLength) guard let topic = String(data: data.subdata(in: topicRange), encoding: .utf8) else { print("Failed to parse topic") return } // Parse payload (adjust start index if QoS > 0, which adds a packet ID) let qosLevel = (data[0] & 0x06) >> 1 var payloadStart = 4 + Int(topicLength) if qosLevel > 0 { payloadStart += 2 } let payloadData = data.subdata(in: payloadStart..<data.count) if let payload = String(data: payloadData, encoding: .utf8) { print("Received message on topic \(topic): \(payload)") } default: print("Unknown MQTT packet type: \(packetType)") } }
A few quick notes:
- Make sure your packet IDs are unique if you send multiple subscription requests.
- If you’re using MQTT 5.0, the packet format has additional fields (like properties) that you’ll need to account for.
- Double-check that your broker supports MQTT over WebSocket and that your topic is correctly formatted.
内容的提问来源于stack exchange,提问作者yusufonderd

