套接字IO未正确关闭连接

时间:2017-09-10 08:57:11

标签: node.js socket.io

我{{}} {{}}日志文件并将新行流式传输到websocket。

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

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

我的tail

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);
});

我做错了什么?

2 个答案:

答案 0 :(得分:1)

正如您在控制台日志中看到的那样,connect和disconnect显示相同的socketID。这表示事件处理程序被多次触发。 每次'connection'路由获取请求时,您都可以从代码中为'/details'定义新的事件处理程序。 所以更好的方法就是......

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);
});

答案 1 :(得分:0)

所以这里的评论指导我解决方案。

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

每次用户点击按钮时,我都会调用连接的启动,每次访问URL时spawn都会tail子进程 以下是我修复它的方法:

<强>插槽

1.按照{alex-rokabilis

的建议,移动io.on('connection'...)处理程序之外的app.get

2.处理了我自己的事件发射器:

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

3.Inside io.on('connection'...),我没有收听tail.stdout事件,而是听取了我的eventEmitter事件,以便能够使用tail之外的app.get {1}}处理程序

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

4.在app.get处理程序中,我会收听tail.stdout.on('data'...并发送一个eventEmitter事件,该事件将在io对象中处理:

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'...内,我为名为closeConnection的事件添加了一个套接字侦听器,该事件向closeConnection发出eventEmitter,从而导致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');

这很难。