Прежде всего, некоторые основы.node.js запускает ваш Javascript как однопоточный, и, таким образом, это однопоточный сервер.Он может делать только одну вещь с вашим Javascript одновременно.Но если вы тщательно его запрограммируете, он может очень хорошо масштабироваться и делать много вещей.
Во-вторых, вы почти никогда не захотите делать while (true)
в Javascript на стороне сервера.Это будет работать вечно и никогда не позволять ничему другому работать на вашем сервере.Ничего другого.
В-третьих, вы пытаетесь создать новую версию этого бесконечного цикла каждый раз, когда подключается новый клиент.Это неправильный дизайн (даже если не было бесконечного цикла).Вам нужен только один экземпляр кода, проверяющий файл, а не N.
Теперь, если вы на самом деле пытаетесь «опросить» изменения в song.txt
и уведомлять клиента о каждом его изменении., вам нужно выбрать разумный интервал времени между проверками файла и использовать таймер.Это будет проверять этот файл очень часто и позволит вашему серверу нормально работать все остальное время.
Вот простая версия, которая опрашивает setInterval()
:
console.log('Server code started!');
const express = require('express');
const app = express();
const server = app.listen(3000);
const fs = require("fs");
let lastSongData = 0;
app.use(express.static('public'));
const io = require('socket.io')(server);
// get initial songData for future use
// there will not be any connected clients yet so we don't need to broadcast it
try {
lastSongData = fs.readFileSync('song.txt');
} catch(e) {
console.log(e, "\nDidn't find song.txt on server initialization");
}
// here, we create a polling loop that notifies all connected clients
// any time the song has changed
const pollInterval = 60*1000; // 60 seconds, ideally it should be longer than this
const pollTimer = setInterval(() => {
fs.readFile('song.txt', (err, songData) => {
if (!err && songData !== lastSongData) {
// notify all connect clients
console.log("found changed songData");
io.emit('update', songData);
lastSongData = songData;
}
});
}, pollInterval);
io.sockets.on('connection', socket => {
console.log("New connection: " + socket.id);
});
Если ваш songData
является двоичным, тогда вам придется изменить способ отправки данных клиенту и способ сравнения данных с предыдущими данными, чтобы вы отправляли и получали двоичные данные, а не строковые данные и сравнивали буферы, а не строки.
Вот некоторые ссылки на отправку двоичных данных с помощью socket.io:
Как отправлять двоичные данные с помощью socket.io?
Как отправить двоичные данные с сервера Node.js socket.io в клиент браузера?
Немного более эффективный способ обнаружения изменений в файле - это использовать fs.watch()
, которыйдолжен уведомить вас об изменениях в файле, хотя вам придется тщательно протестировать его на любой платформе, на которой вы работаете, чтобы убедиться, что он работает так, как вы хотите.Эта функция имеет ряд предостережений платформы (она не работает одинаково на всех платформах), поэтому вы должны тщательно протестировать ее на своей платформе, чтобы увидеть, можете ли вы использовать ее для того, что вы хотите.
console.log('Server code started!');
const express = require('express');
const app = express();
const server = app.listen(3000);
const fs = require("fs");
let lastSongData = 0;
app.use(express.static('public'));
const io = require('socket.io')(server);
// get initial songData for future use
// there will not be any connected clients yet so we don't need to broadcast it
try {
lastSongData = fs.readFileSync('song.txt');
} catch(e) {
console.log(e, "\nDidn't find song.txt on server initialization");
}
// ask node.js to tell us when song.txt is modified
fs.watch('song.txt', (eventType, filename) => {
// check the file for all eventTypes
fs.readFile('song.txt', (err, songData) => {
if (!err && songData !== lastSongData) {
// notify all connect clients
console.log("found changed songData");
lastSongData = songData;
io.emit('update', songData);
}
});
});
io.sockets.on('connection', socket => {
console.log("New connection: " + socket.id);
});
Из исходного кода неясно, нужно ли отправлять songData
каждому новому соединению (независимо от того, было оно недавно изменено или нет).
Если это так, вы можетепросто измените свой обработчик событий подключения на это:
io.sockets.on('connection', socket => {
console.log("New connection: " + socket.id);
// send most recent songData to each newly connected client
if (lastSongData) {
socket.emit('update', lastSongData);
}
});