javascript - node.js + socket.io : auction website development

标签 javascript node.js socket.io node-redis node-cluster

我目前正在使用 node.js 和 socket.io 编写拍卖脚本。但是网站是使用 PHP 和 MySQL 开发的。这里我只使用 node.js + socket.io 进行拍卖。该网站将有 500-1000 名登录用户在拍卖期间查看单个页面。只有一件元素会被拍卖,并且会在一天内售出一次。

我将向从服务器到客户端的所有用户广播(发射)一个倒数计时器。在服务器端,我将使用 setInterval(),1 秒的递归 setTimeout() 来倒计时到拍卖结束时间。除此之外,唯一发送的其他消息将是当前出价从单个客户端传递到服务器,然后广播给所有人。这种做法靠谱吗?它能处理服务器上的使用吗?在这里,我测试了 500 个用户意味着在浏览器中挂起计时器。

服务器.js

var cluster = require('cluster');
var app = require('express')();
//var http = require('http');
var https = require('https');
var socket = require('socket.io');
var redis = require('redis');
var redisAdapter = require('socket.io-redis');
var request = require('request');
var fs = require('fs');

var options = {
    key: fs.readFileSync('keys/e1317_0f2c9_71565598d419e37e376ccef5c2827113.key'),
    cert: fs.readFileSync('certs/e1317_0f2c9_1468152279_2dc46c1f2cc135a.crt'),
    ca: fs.readFileSync('cabundles/90490a5c829d2aca24f22b5820864c6e_1935558000.cabundle')
};

//var server = http.createServer( app );
var server = https.createServer(options, app);
var io = socket.listen(server);

var port = process.env.PORT || 8080;
var workers = process.env.WORKERS || require('os').cpus().length;

var redisUrl = process.env.REDISTOGO_URL || 'redis://127.0.0.1:6379';
var redisOptions = require('parse-redis-url')(redis).parse(redisUrl);
var pub = redis.createClient(redisOptions.port, redisOptions.host, {
    detect_buffers: true,
    return_buffers: true,
    auth_pass: redisOptions.password
});
var sub = redis.createClient(redisOptions.port, redisOptions.host, {
    detect_buffers: true,
    return_buffers: true,
    auth_pass: redisOptions.password
});

io.adapter(redisAdapter({
    pubClient: pub,
    subClient: sub
}));

console.log('Redis adapter started with url: ' + redisUrl);

io.sockets.on('connection', function(client) {
    //console.log('first');
    client.on('nauction', function(data) {
        io.sockets.emit('nauction', data);
    });
});

io.on('connection', function(socket) {
    //console.log('in');
    console.log('connected client count:' + io.sockets.sockets.length);
    var recursive = function() {
        //console.log("It has been one second!");
        if (io.sockets.sockets.length > 0) {
            request('https://www.example.com/file.php', function(error, response, body) {
                if (!error && response.statusCode == 200) {
                    data = JSON.parse(body);
                    socket.volatile.emit('auction_data', {
                        'auction_data': data
                    });
                    //console.log(data);
                } else {
                    //console.log('else');
                    console.log(error);
                }
            });
        } //else{
        //console.log('No clients connected now');
        //}
        setTimeout(recursive, 1000);
    }
    recursive();
    socket.on("disconnect", function() {
        console.log('clear interval')
            //clearInterval(interval);
        clearTimeout(recursive);
    });
});

if (cluster.isMaster) {
    console.log('start cluster with %s workers', workers - 1);
    workers--;
    for (var i = 0; i < workers; ++i) {
        var worker = cluster.fork();
        console.log('worker %s started.', worker.process.pid);
    }

    cluster.on('death', function(worker) {
        console.log('worker %s died. restart...', worker.process.pid);
    });
} else {
    start();
}

function start() {
    server.listen(port, function() {
        console.log('listening on *:' + port);
    });
}

客户端.js

socket.on('auction_data', function(auction_details) {
    //console.log(auction_details);
    $.each(auction_details, function(keys, values) {
        //countdwon formation
        var tm, days, hrs, mins, secs;
        days = value.auction_data.time.days;
        if (value.auction_data.time.hours < 10) {
            hrs = ("0" + value.auction_data.time.hours);
        } else {
            hrs = value.auction_data.time.hours;
        }
        if (value.auction_data.time.mins < 10) {
            mins = ("0" + value.auction_data.time.mins);
        } else {
            mins = value.auction_data.time.mins;
        }
        if (value.auction_data.time.secs < 10) {
            secs = ("0" + value.auction_data.time.secs);
        } else {
            secs = value.auction_data.time.secs;
        }
        if (days == 0) {
            tm = '' + hrs + '' + '' + mins + '' + '' + secs + '';
        } else {
            tm = '' + days + '' + '' + hrs + '' + '' + mins + '' + '' + secs + '';
        }
        $('#auction_' + value.auction_data.product_id + " .countdown").html(tm);
    });
});

我正在等待您解决浏览器挂起问题的答案。

最佳答案

第一个问题:这种做法靠谱吗?

没有必要每隔一秒向每个客户端发送一次时间。只需在他们第一次访问时向他们发送时间,并使用本地计时器(在他们的本地页面上)来减少每秒的时间。

您还需要检查每次出价的服务器时间(更安全)。

如果这对您来说不够“安全”,请发送带有更改出价的时间。您只需在实际出价发生变化时(使用广播)或用户加入网站时发送实际出价(只需将其发送给他)。

第二个问题: 它能处理服务器上的使用吗?

是和否

如果您的服务器足够好(每个 5 美元的服务器都可以提供无限流量), 你不应该惹上麻烦。仅当您的脚本非常非常糟糕并且存在内存泄漏时。

现在有几个提示:

  • 永远不要相信用户输入 - 在使用之前先解析它!
  • 在服务器上重新计算您从客户端获得的所有内容。
  • 只发送客户需要的东西。他不需要关于他不使用的东西的信息。

如果这是您希望得到的答案,请选择左侧的绿色箭头。 如果没有,请在此处发表评论,我会提供更多提示。

关于javascript - node.js + socket.io : auction website development,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34993106/

相关文章:

javascript - addListener 事件——错误

javascript - 如何清除 angularjs 中的 uib-typeahead 下拉列表

javascript - POST 500(内部服务器错误)无法在 Node 服务器上使用 React JS 发布表单数据

javascript - Angular .js : How can I avoid caching services?

node.js - Socket.IO + Express 框架 |从 Express Controller 和路由器发射/发射

javascript - 使用 Node.js 和 Swift 服务器的 Socket.IO 未检测到连接? [即将颁奖]

javascript - 使用 _.throttle 限制 .apply 方法的速率

javascript - Python ctypes.c_int 到 Perl XS(或非 XS)转换(Javascript 签名 32 位位移运算符转换)

javascript - Google Analytics 服务器端授权获取页面浏览计数分析数据并将其显示在首页上的随机访问者

javascript - 在 GAE 上运行 Websocket