Node.js Socket.IO服务端与iOS应用异步收发消息异常问题咨询
问题根因
你遇到的所有异常表现本质都是prompt-sync库的同步阻塞特性导致的:
Node.js 是单线程事件驱动架构,prompt-sync触发输入等待时会完全阻塞整个事件循环,所有IO事件(包括Socket.IO接收到的iOS端消息、定时器任务)都会被挂起,直到你完成输入才会批量执行所有积压的事件。同时你原有逻辑里send函数仅执行1次,第一次输入完成后就不会再监听控制台输入,所以会出现发送一次就失效的问题。
解决方案
替换同步的prompt-sync为Node.js内置的异步控制台输入模块readline,异步监听输入不会阻塞事件循环,收发逻辑可以完全独立运行互不干扰。
修正后完整代码
var express = require('express'); var readline = require('readline'); var app = express(); var server = require('http').createServer(app); var io = require('socket.io')(server); // 初始化控制台异步输入实例 const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); var connections = []; // 存储当前活跃的socket实例,用于发送消息 var activeSocket = null; server.listen(process.env.PORT || 2229); console.log('Server is running...'); // 全局监听控制台输入,异步非阻塞 rl.on('line', (input) => { if (activeSocket) { activeSocket.emit('iOS Client Port', { msg: input.trim() }); console.log('已发送消息:', input.trim()); } else { console.log('暂无iOS客户端连接,消息未发送'); } // 继续等待下一次输入 rl.prompt(); }); // 初始化提示符 rl.prompt(); io.sockets.on('connection', function (socket) { connections.push(socket); activeSocket = socket; console.log('Connect: %s sockets are connected', connections.length); io.sockets.emit('iOS Client Port', { msg: 'Hi from server' }); // 监听iOS端消息,随时可以接收不会被阻塞 socket.on('NodeJS Server Port', function (data) { // 打印消息前先清掉当前行的提示符,避免输出混乱 process.stdout.write('\r'); console.log('收到iOS端消息:', data); // 重新输出提示符 rl.prompt(); }); // 处理连接断开 socket.on('disconnect', () => { connections = connections.filter(item => item !== socket); if (activeSocket === socket) { activeSocket = connections[connections.length - 1] || null; } console.log('Disconnect: %s sockets are connected', connections.length); rl.prompt(); }); });
改动说明
- 移除了同步阻塞的
prompt-sync依赖,改用异步的readline模块监听控制台输入,不会阻塞Socket.IO的消息接收,iOS端的消息可以实时打印不会积压 - 控制台输入逻辑全局仅注册一次,每次输入完成后会自动等待下一次输入,不会出现发送一次就无法继续发消息的问题
- 新增了连接断开的处理逻辑,避免客户端断开后发送消息报错
- 优化了控制台输出格式,避免收到消息和输入提示符互相干扰
内容的提问来源于stack exchange,提问作者michaeldylann
相关产品推荐
相关产品推荐

