我{{}} {{}}日志文件并将新行流式传输到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);
});
我做错了什么?
答案 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)
所以这里的评论指导我解决方案。
socket
和tail
都有重复的事件处理程序。
每次用户点击按钮时,我都会调用连接的启动,每次访问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');
这很难。