Expo与Node.js Socket连接异常:发送4条消息后无法再发送
Expo端Socket发送4条消息后无法继续发送的问题排查
问题背景
我用Expo和Node.js开发的应用原本运行正常,新增ReactJS管理面板后,实现了用户与管理员的Socket即时聊天功能。网页端管理员发送消息无异常,但Expo端用户接收消息正常,回复消息时,恰好发送4条后就无法再通过socket.emit发送消息,但仍能接收消息,服务器显示Socket未断开。
使用版本:socket.io@3.0.4,socket.io-client@3.0.4
Expo端相关代码
const [messages, setMessages] = useState([]); const[socket,setSocket]=useState(null) const message = route.params.message; useEffect(() => { const newsocket =io.connect("http://IP_ADDRESS:9000") setMessages(message.Messages) newsocket.on('connect', msg => { console.log(`user: ${user.id} has joined conversation ${message.id}`,'connection socket id', newsocket.id) setSocket(newsocket) newsocket.emit('subscribe', message.id); }); newsocket.on("send_message", (msg) => { console.log('msg',msg) setMessages(messages => [msg.data, ...messages]); }); return(()=>{ console.log(`user: ${user.id} left the room ${message.id} --- socketid ${newsocket.id}`) newsocket.disconnect() }); }, []); const onSend = async(conversationId,senderId,receiverId,message) => { const response = await messagesApi.sendMessage({conversationId,senderId,receiverId,message}); if (!response.ok) return setError(true); console.log("sent") const to = (user.id===route.params.message.user?route.params.message.admin:route.params.message.user) socket.emit('message', { to: to, from: user.id, message,conversationId,data:response.data }); if(response.ok){ setText("") } };
Node.js服务端相关代码
const express = require("express"); const users = require("./routes/users"); const auth = require("./routes/auth"); const messages = require("./routes/messages"); const helmet = require("helmet"); const compression = require("compression"); const config = require("config"); const app = express(); var cors = require('cors') app.use(cors()) //Socket.io const http = require("http"); const socket = require("socket.io"); const server=http.createServer(app); const io =socket(server,{ cors: { origin: ["http://localhost:3000","192.168.1.4:9000"], methods: ["GET", "POST"], credentials: true }}) io.on('connection',(socket)=>{ // connection console.log('User '+socket.id+' connected') // joining a room socket.on('subscribe', (room)=> { console.log('user socket',socket.id,'joining room', room); socket.join(room); }); // send message within room socket.on('message', (data) => { io.in(data.conversationId).emit('send_message', { message: data.message, receiverId: data.to,senderId:data.from,id:data.conversationId,data:data.data }); }) // waiting to enter room socket.on('waiting', (data)=> { console.log('user',socket.id, 'is waiting.'); }); // disconnect socket.on('disconnect',(reason)=>{ socket.disconnect() console.log('socket disconnected',socket.disconnect().disconnected) console.log('USER DISCONNECTED',socket.id) if (reason === "io server disconnect") { // the disconnection was initiated by the server, you need to reconnect manually socket.connect(); console.log('socket reconnected',socket.id) } }) }) app.use(express.json({limit: '50mb'})); app.use(express.urlencoded({limit: '50mb', extended: true, parameterLimit: 500000})); app.use(express.static("public")); app.use(helmet()); app.use(compression()); app.use("/api/users/", users); app.use("/api/auth/", auth); app.use("/api/messages", messages); const port = process.env.PORT || config.get("port"); server.listen(port, function() { console.log(`Server started on port ${port}...`); });
问题原因分析
核心原因:Socket.IO客户端缓冲区满阻塞
Socket.IO v3客户端默认配置了maxBufferSize: 4,即最多允许4条未被服务端确认的待发送消息。当你连续发送消息但未收到服务端的确认回复时,客户端的待发送队列会被填满,后续的emit调用会被阻塞,直到之前的消息得到确认。
你的代码中,客户端发送message事件时没有设置确认回调,服务端也没有对该事件发送确认响应,导致前4条消息发送后,缓冲区耗尽,无法继续发送新消息。同时因为Socket连接并未断开,所以仍能正常接收消息。
次要问题:服务端disconnect事件处理错误
服务端的disconnect回调中重复调用socket.disconnect(),并尝试对已断开的socket实例调用connect(),这会导致无效的socket操作,可能干扰正常的连接状态管理。
解决方案
方案1:添加消息确认机制
修改服务端message事件处理,添加确认回复:
socket.on('message', (data, callback) => { io.in(data.conversationId).emit('send_message', { message: data.message, receiverId: data.to,senderId:data.from,id:data.conversationId,data:data.data }); // 向客户端发送确认 callback({ status: 'success' }); })
客户端发送消息时添加确认回调:
socket.emit('message', { to: to, from: user.id, message,conversationId,data:response.data }, (ack) => { console.log('消息已确认:', ack); });
方案2:调整客户端缓冲区大小
在客户端连接时配置更大的缓冲区(仅作为临时方案,推荐优先使用确认机制):
const newsocket = io.connect("http://IP_ADDRESS:9000", { maxBufferSize: 100 // 根据实际需求调整 });
方案3:修复服务端disconnect事件处理
移除无效的socket操作,简化回调逻辑:
socket.on('disconnect',(reason)=>{ console.log('用户断开连接:', socket.id, '原因:', reason) // 无需手动调用disconnect,事件触发时连接已断开 // 客户端默认会自动重连,无需服务端尝试重连失效实例 })
内容的提问来源于stack exchange,提问作者kd12345
相关产品推荐
相关产品推荐

