【问题标题】:Socket IO not properly closing connection套接字 IO 未正确关闭连接
【发布时间】:2017-09-11 19:23:13
【问题描述】:

我正在tail输入日志文件并将新行流式传输到 websocket。

由于我有多个日志,我让用户选择日志文件,然后获取该日志的详细信息。

问题是,当我关闭连接以查看不同的日志时,连接会做一些奇怪的事情,当我再次启动它时,它会两次传输数据。如果我关闭连接并重新打开它,它会传输 3 倍的数据,依此类推。

我的package.json

{
    "socket.io": "^2.0.3",
    "socket.io-client": "^2.0.3"
}

客户端

$("#detailsBtn").click(function (e) {
    e.preventDefault();
    $.get('/get/details', {
        // some-data
    }, () => {
        if (socket) socket.close();
        socket = io('http://localhost:4000', {forceNew: true});
        socket.on('connect', () => {
            console.log('connected');
        });
        socket.on('newLine', function (msg) {
            // do-stuff
        });
    });
});
$('#closeBtn').click(function () {
    socket.disconnect();
    socket.close();
});

服务器端

app.get('/details', (req, res) => {
    const tail = spawn('ssh', ['root@' + req.query.srv, req.query.script]);
    io.on('connection', function (socket) {
        console.log(`connect ${socket.id}`);
        socket.on('disconnect', () => {
            console.log(`DISconnected ${socket.id}`);
        });
        tail.stdout.on('data', function (data) {
            socket.emit('newLine', {message: data});
        });
    });
    return res.sendStatus(200);
});

现在在模拟按钮点击时,我希望套接字和连接关闭,以便创建一个新的。

服务器控制台日志(每次我只点击一次按钮)

Server listening on localhost:4000

**click on detailsBtn**
GET /get/details?srv=myserver.google.com&script=%2Fusr%2Fbin%2Ftail 304 16.003 ms - -
connect YyYHFI9CARpBHaxoAAAB
**click on closeBtn**
DISconnected YyYHFI9CARpBHaxoAAAB

**click on detailsBtn**
GET /get/details?srv=myserver.google.com&script=%2Fusr%2Fbin%2Ftail 304 6.308 ms - -
connect vzfBnUPHUqYXd5qaAAAC
connect vzfBnUPHUqYXd5qaAAAC
**click on closeBtn**
DISconnected vzfBnUPHUqYXd5qaAAAC
DISconnected vzfBnUPHUqYXd5qaAAAC

**click on detailsBtn**
GET /get/details?srv=myserver.google.com&script=%2Fusr%2Fbin%2Ftail 304 4.677 ms - -
connect 3quEe5G1gFDJ2BvrAAAD
connect 3quEe5G1gFDJ2BvrAAAD
connect 3quEe5G1gFDJ2BvrAAAD
**click on closeBtn**
DISconnected 3quEe5G1gFDJ2BvrAAAD
DISconnected 3quEe5G1gFDJ2BvrAAAD
DISconnected 3quEe5G1gFDJ2BvrAAAD

我做错了什么?

【问题讨论】:

  • 这样的症状通常是由重复的事件处理程序引起的。

标签: node.js socket.io


【解决方案1】:

正如您在控制台日志中看到的,连接和断开连接显示相同的 socketID。这表明事件处理程序被触发了很多次。 每次'/details' 路由收到请求时,您都可以从您的代码中为'connection' 定义一个新的事件处理程序。 所以更好的方法是......

io.on('connection', function (socket) {
    console.log(`connect ${socket.id}`);
    socket.on('disconnect', () => {
        console.log(`DISconnected ${socket.id}`);
    });
    tail.stdout.on('data', function (data) {
        socket.emit('newLine', {message: data});
    });
});
app.get('/details', (req, res) => {
   const tail = spawn('ssh', ['root@' + req.query.srv, req.query.script]);
   return res.sendStatus(200);
});

【讨论】:

  • 它抛出错误:tail is not defined。我还尝试将整个 tail.stdout 部分移动到 app.get 然后 socket is not defined
【解决方案2】:

所以这里的 cmets 将我引向了解决方案。

sockettail 都有重复的事件处理程序。

每次用户单击按钮时,我都会调用连接的初始化,并且每次访问 URL 时,我都会 spawned 一个 tail 子进程 这是我修复它的方法:

套接字

1.按照@alex-rokabilis 的建议,将io.on('connection'...) 移出app.get 处理程序

2.创建我自己的事件发射器:

const events = require('events');
const eventEmitter = new events.EventEmitter();

3.在io.on('connection'...) 内部,我没有监听tail.stdout 事件,而是监听了我的eventEmitter 事件,以便能够在app.get 处理程序之外使用tail

io.on('connection', function (socket) {
    eventEmitter.on('newLine', (data) => {
        socket.emit('newLine', {line: data});
    });
});

4.在app.get 处理程序中,我监听tail.stdout.on('data'... 并发送将在io 对象内部处理的eventEmitter 事件:

app.get('/details', (req, res) => {
    let tail = spawn('ssh', ['root@' + req.query.srv, req.query.script]);
    tail.stdout.on('data', (data) => {
        eventEmitter.emit('newLine', data.toString().replace(/\n/g, '<br />'));
    });
});

5.在客户端,我将 io 初始化移到了 ajax 调用之外,以一种我可以在脚本中进一步使用的方式定义了套接字。

let socket = io('http://localhost:4000', {forceNew: true});
socket.on('connect', () => {
    console.log('connected');
});
socket.on('newLine', function (msg) {
    // do-stuff
});

$("#detailsBtn").click(function (e) {
    e.preventDefault();
    $.get('/get/details', {
        // some-data
    });
});

尾巴

这有点难找,我一直认为问题出在 socket-io 而不是tail

io.on('connection'... 中,我为名为@9​​87654343@ 的事件添加了一个套接字侦听器,该事件向我的eventEmitter 发出closeConnection,这反过来又杀死了tail 子进程:

io.on('connection', function (socket) {
    eventEmitter.on('newLine', (data) => {
        socket.emit('newLine', {line: data});
    });
    socket.on('closeConnection', () =>{
        console.log('got connection close from client');
        eventEmitter.emit('closeConnection');
    });
});

app.get 控制器内部:

app.get('/details', (req, res) => {
    let tail = spawn('ssh', ['root@' + req.query.srv, req.query.script]);
    tail.stdout.on('data', (data) => {
        eventEmitter.emit('newLine', data.toString().replace(/\n/g, '<br />'));
    });
    eventEmitter.on('closeConnection', () => {
        tail.stdin.pause();
        tail.kill();
    });
});

而在客户端,每次我想关闭连接时,我只是:

socket.emit('closeConnection');

这很难。

【讨论】:

    猜你喜欢
    • 2018-12-14
    • 2011-06-29
    • 1970-01-01
    • 2011-02-06
    • 2012-02-10
    • 2014-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多