Skip to content

Instantly share code, notes, and snippets.

@felixge
Forked from rmehner/.gitignore
Created October 6, 2011 15:36
Show Gist options
  • Save felixge/1267712 to your computer and use it in GitHub Desktop.
Save felixge/1267712 to your computer and use it in GitHub Desktop.
.DS_Store
node_modules
var options = require('commander');
var transports = {
'xhr-polling': require('./transport/xhr_polling'),
};
options
.option('-p, --port [port]', 'The port to connect to [3030]', 3030)
.option('-h, --host [host]', 'The host to connect to [localhost]', 'localhost')
.option('-c, --clients [clients]', 'The number of total clients', 10)
.option('-m, --messages [messages]', 'The number of messages to send per sec [0.1]', 0.1)
.option('-i, --interval [interval]', 'The interval in seconds to accumlate stats [10]', 10)
.option('-t, --transport [transport]', 'The transport type to use by the client [xhr-polling,websocket]', 'xhr-polling')
.option('-%, --percentile [percentile]', 'The percentile to calculate latency for [95]', 95)
.parse(process.argv);
function Benchmark() {
this.clients = [];
this.maxClients = null;
this.interval = null;
this.transport = null;
this.connectedCounter = 0;
this.percentile = null;
this.responseTimes = [];
}
Benchmark.create = function(options) {
var instance = new Benchmark();
instance.maxClients = options.clients;
instance.host = options.host;
instance.port = options.port;
instance.interval = options.interval;
instance.transport = options.transport;
instance.percentile = options.percentile;
return instance;
};
Benchmark.prototype.start = function() {
for (var i = 0; i < this.maxClients; i++) {
this.connectClient();
}
};
Benchmark.prototype.connectClient = function() {
var client = transports[this.transport].create(this.port, this.host);
client.connect();
client
.on('connect', this.handleConnect.bind(this, client))
.on('message', this.handleMessage.bind(this, client))
.on('error', this.handleError.bind(this, client));
this.clients.push(client);
};
Benchmark.prototype.handleMessage = function(client, message) {
var time = message.args[0].time;
var latency = Date.now() - time;
this.responseTimes.push(latency);
if (this.responseTimes.length === this.clients.length) {
this.analyze();
this.responseTimes = [];
}
};
Benchmark.prototype.analyze = function() {
this.responseTimes.sort(function(a, b) {
if (a === b) return 0;
return (a < b)
? -1
: 1;
});
var index = Math.ceil(this.responseTimes.length * this.percentile / 100);
var responseTime = this.responseTimes[index];
console.error(
'%s percentile response time for %d clients: %d',
this.percentile,
this.clients.length,
responseTime
);
};
Benchmark.prototype.handleConnect = function(client, message) {
this.connectedCounter++;
};
Benchmark.prototype.handleError = function(client, error) {
var index = this.clients.indexOf(client);
console.error('Error from client %d: %s', index, error);
};
var benchmark = Benchmark.create(options);
benchmark.start();
{
"author": "Robin Mehner <robin@coding-robin.de>",
"name": "socketio-bench-server",
"description": "Small socket.io server bench",
"version": "0.0.0",
"repository": {
"url": ""
},
"engines": {
"node": "~0.4.12"
},
"dependencies": {
"socket.io": "~0.8.4",
"commander": "~0.2.0",
"socket.io-client": "~0.8.4"
},
"devDependencies": {}
}
var port = 3030;
var interval = 1000;
var duration = 10 * 1000;
var receivedCounter = 0;
var sockets = [];
var io = require('socket.io').listen(port);
io.configure(function() {
io.set('log level', 1);
});
io.sockets.on('connection', function (socket) {
sockets.push(socket);
socket.on('chat.send', function(data) {
receivedCounter++;
});
});
setInterval(function() {
sockets.forEach(function(socket) {
socket.emit('chat.msg', {
msg: 'JavaScript motherfucker. Do you speak it!',
time: Date.now(),
});
});
}, interval);
setInterval(function() {
console.log('Received %d requests per second', receivedCounter / duration * 1000);
receivedCounter = 0;
}, duration);
var program = require('commander');
var io = require('socket.io-client')
program
.option('-p, --port [port]', 'The port to connect to [3030]', 3030)
.option('-h, --host [host]', 'The host to connect to [localhost]', 'localhost')
.option('-c, --clients [clients]', 'The number of total clients', 1000)
.option('-m, --messages [messages]', 'The number of messages to send per sec [0.1]', 0.1)
.parse(process.argv);
function WebsocketClient() {
this.connection = undefined;
}
WebsocketClient.prototype.connect = function() {
this.connection = io.connect('http://' + program.host + ':' + program.port);
}
WebsocketClient.prototype.sendMsg = function() {
if (this.connection.socket.connected) {
this.connection.emit('chat.send', {msg: 'Your mum'});
}
}
WebsocketClient.prototype.sendMessages = function() {
var that = this;
setInterval(function() {
that.sendMsg();
}, 1000 / program.messages);
}
for (var i = 0; i < program.clients; i++) {
var client = new WebsocketClient();
client.connect();
client.sendMessages();
}
var http = require('http');
var querystring = require('querystring');
var clients = [];
var EventEmitter = require('events').EventEmitter;
var util = require('util');
module.exports = XhrPolling;
util.inherits(XhrPolling, EventEmitter);
function XhrPolling() {
EventEmitter.call(this);
this.port = null;
this.host = null;
this.connecting = false;
this.connected = false;
this.sessionId = null;
this.transport = 'xhr-polling';
this._request = null;
}
XhrPolling.create = function(port, host) {
var instance = new this();
instance.port = port;
instance.host = host;
return instance;
};
XhrPolling.prototype.connect = function() {
this.connecting = true;
this.handshake();
};
XhrPolling.prototype.handshake = function() {
var self = this;
this.request(function(err, response) {
if (err) return self.emit('error', err);
self.sessionId = response[0];
self.poll();
});
};
XhrPolling.prototype.poll = function() {
var self = this;
this.request(function(err, response) {
if (err) return self.emit('error', err);
if (response[0] === '7') {
self.emit('error', new Error('Error: ' + JSON.stringify(response)));
}
// Connected
if (response[0] === '1') {
self.connected = true;
self.connecting = false;
self.emit('connect');
self.poll();
return;
}
// Event
if (response[0] === '5') {
var message = JSON.parse(response[3]);
self.emit('message', message);
self.poll();
return;
}
self.emit('error', new Error('Not implemented: ' + JSON.stringify(response)));
});
};
XhrPolling.prototype.request = function(endpoint, cb) {
if (typeof endpoint === 'function') {
cb = endpoint;
endpoint = '';
}
if (endpoint) endpoint = '/' + endpoint;
var session = '';
if (this.sessionId) {
session = this.transport + '/' + this.sessionId;
}
var path = '/socket.io/1/' + session + endpoint;
var options = {
host: this.host,
port: this.port,
path: path,
};
var agent = http.getAgent(options.host, options.port)
agent.maxSockets = 1000;
this._request = http.get(options, this.handleResponse.bind(this, cb));
var self = this;
this._request.on('error', function(err) {
self.emit('error', err);
});
};
XhrPolling.prototype.handleResponse = function(cb, res) {
var data = '';
res.setEncoding('utf8');
res
.on('data', function(chunk) {
data += chunk;
})
.on('end', function() {
var message = [];
for (var i = 0; i < 3; i++) {
var end = data.indexOf(':');
message[i] = data.substr(0, end);
data = data.substr(end + 1);
}
message[3] = data;
cb(null, message);
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment