You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 08:55:18