如何通过MQTT、Node.js、Socket.IO向Flutter发送实时数据并解决接收异常问题
服务端问题修复
你现有服务端存在4个核心问题:
- 未启动HTTP服务监听指定端口,Socket.IO服务根本未对外暴露
- 未配置Socket.IO跨域规则,跨域请求会被直接拦截
- MQTT客户端连接成功后未订阅目标主题,无法触发
message事件回调 - 模板字符串语法错误(单引号包裹模板变量,未使用反引号,仅影响日志输出不影响功能)
修正后的完整服务端代码:
const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); var http = require('http'); const port = process.argv.slice(2)[0] || 3000; // 缺省端口兜底 const app = express(); app.use(bodyParser.json()); const mqtt = require('mqtt') const client = mqtt.connect('mqtt://broker.hivemq.com') var firebase = require('firebase'); const server = http.Server(app) // 配置Socket.IO允许跨域 const socketIo = require('socket.io')(server, { cors: { origin: "*", methods: ["GET", "POST"] } }) // MQTT连接成功后订阅目标主题,替换成你实际的业务主题 client.on('connect', () => { client.subscribe('your/Target/MQTT/Topic', (err) => { if (!err) console.log('MQTT主题订阅成功') }) }) function mqtt_messsageReceived(topic, message, packet) { if(message){ let messageObject = JSON.parse(message) insertMessage(topic, messageObject, packet) // 全局广播给所有已连接的客户端 socketIo.emit('geocoordinateData', messageObject); } } socketIo.on('connection', (socket) =>{ // 修复模板字符串语法,用反引号包裹 console.log(`${socket.id} 已连接`) socket.emit('request', 'ok'); }) // 启动服务监听端口 server.listen(port, () => { console.log(`服务运行在端口${port}`) }) client.on('message', mqtt_messsageReceived)
客户端问题修复
Flutter端socket_io_client默认使用长轮询传输,和服务端默认配置不匹配,且你未主动触发连接操作:
- 初始化时必须指定
transports: ['websocket']参数,强制使用WebSocket协议 - 初始化完成后调用
socket.connect()主动发起连接请求
修正后的Flutter端代码:
import 'package:flutter/material.dart'; import 'package:socket_io_client/socket_io_client.dart' as IO; void main() { // 补充transports配置,替换成你自己的服务地址 IO.Socket socket = IO.io('https://xxxx.herokuapp.com/', IO.OptionBuilder() .setTransports(['websocket']) .disableAutoConnect() .build() ); print('mainohhhhh'); socket.onConnect((data) { print('connect'); socket.emit('msg', 'test'); print('socketohhhhh'); }); socket.on('geocoordinateData', (data) => print(data)); // 主动发起连接 socket.connect(); runApp(const MyApp()); } // 补充MyApp空实现避免编译报错,你可以保留自己的原有实现 class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp(home: Scaffold(appBar: AppBar(title: const Text("Socket测试")))); } }
验证步骤
- 先启动服务端,确认打印
服务运行在端口xxx和MQTT主题订阅成功日志 - 启动Flutter客户端,确认服务端打印
{socket.id} 已连接日志,同时客户端打印connect日志,证明连接正常 - 向你订阅的MQTT主题发送JSON格式消息,确认客户端控制台会打印收到的
geocoordinateData事件数据
内容的提问来源于stack exchange,提问作者gbeto Jean-José
相关产品推荐
相关产品推荐

