Reputation: 441
My requirement is a little bit different, don't know even if it's achievable.
I am using Node.js for developing backend application server. This server basically does two jobs:
(1) Serving clients: My clients are all mobile phones who will be sending HTTP(S) request and after receiving the response will close the session.
(2) Calling some other asynchronously working service: The server, on the other hand, will be connected to some other server which works over just TCP/IP connection and not HTTP. Asynchronous here means, the server will send a request and should not wait for a response. The response will be received through same TCP/IP connection.
So the flow I want to achieve is:
To represent the above flow I have attached the below image.
In the above image the TCP/IP Server is managed by some other provider.
I wrote the following code in node.js which works perfectly as per our requirement some times, but some times it sends incorrect response to the HTTP request. I did not write any code to handle this issue.
var net = require('net');
var client = new net.Socket();
client.connect(2202, 'example_ip', function () {
console.log('Connected');
// client.write('Hello, server! Love, Client.');
});
//Lets require/import the HTTP module
var http = require('http');
//Lets define a port we want to listen to
const PORT = 8080;
//We need a function which handles requests and send response
function handleRequest(request, response) {
var body = '';
request.on('data', function (chunk) {
body += chunk;
});
request.on('end', function () {
console.log('Received request from JMeter------------>>>');
// console.log(body);
client.write(body);
var count = 0;
client.on('data', function (data) {
console.log('<<<------------Received from SSM: ' + data);
response.end(data);
// client.destroy(); // kill client after server's response
});
});
client.on('close', function () {
console.log('Connection closed');
});
}
//Create a server
var server = http.createServer(handleRequest);
//Lets start our server
server.listen(PORT, function () {
//Callback triggered when server is successfully listening. Hurray!
console.log("Server listening on: http://localhost:%s", PORT);
});
Please some one guide me to solve this issue.
Upvotes: 4
Views: 3197
Reputation: 998
TCP streams don't work like WebSocket streams ( as you expect ). You need to use your own protocol to communicate with a TCP server. Keep in mind that HTTP clients are many and you have only one TCP connection to handle them, so use requestIds like below, code explains itself.
Not tested, but you can get the idea.
shared.js
exports.tcp = {
host: 'example_ip',
port: 2202
};
exports.http = {
host: 'localhost',
port: 8080
};
/**
* TCP "guarantees" that a receiver will receive the reconstituted
* stream of --> BYTES <-- as it was originally sent by the sender.
*
* eg. if written message = 'How are you today?'
* the messages can come to us as follows:
*
* 'How ar'
* 'e you '
* 'today?'
*
* so we need to use a simple protocol to handle messages
*/
exports.protocol = protocol;
function protocol(options) {
if (!options) options = {};
this.END_OF_MESSAGE = options.endOfMessage || '\0';
this.END_OF_PART = options.endOfPart || '\1';
this.dataBuffer = '';
}
protocol.prototype.packMessage = function(id, body) {
return [id, body].join( this.END_OF_PART ) + this.END_OF_MESSAGE;
};
protocol.prototype.unpackMessage = function(message) {
var parts = message.toString('utf8').split( this.END_OF_PART );
return {id: parts.shift(), body: parts.shift()};
};
protocol.prototype.extractMessages = function(data, callback) {
this.dataBuffer += data.toString('utf8');
if (this.dataBuffer.indexOf(this.END_OF_MESSAGE) !== -1)
{
var messages = this.dataBuffer.split(this.END_OF_MESSAGE);
var incomplete = this.dataBuffer.slice(-1) === this.END_OF_MESSAGE
? '' : messages.pop();
messages.forEach(function(message)
{
if (message !== '') {
callback( this.unpackMessage(message) );
}
});
this.dataBuffer = incomplete;
// rest of 'data'
}
/**
if (Buffer.byteLength(this.dataBuffer, 'utf8') > 10240) { // 10KB
console.log('[!] socket flooded');
this.dataBuffer = '';
}
*/
};
protocol.prototype.reset = function() {
this.dataBuffer = '';
};
httpServer.js
var http = require('http');
var net = require('net');
var shared = require('./shared.js');
var protocol = new shared.protocol();
var server = http.createServer(handleRequest);
server.listen(shared.http.port, shared.http.host, function() {
console.log('HTTP server listening: %s:%s', shared.http.host, shared.http.port);
});
function handleRequest(request, response) {
var body = '';
var requestId = nextId++;
var eventName = 'message' + requestId;
request.on('data', function(chunk) {
body += chunk.toString('utf8');
});
request.on('end', function()
{
// ref#2
client.write( protocol.packMessage(requestId, body) );
// ref#3
client.once(eventName, function(data) {
clearTimeout(timeoutId);
response.end(data);
});
});
var timeoutId = setTimeout(function() {
client.removeListener(eventName);
response.end('timeout');
}, 10000); // 10 sec.
/**
* [!] Don't do this; you are adding just another 'data' event to
* the TCP client for EVERY http request !?
*
* request: UNIQUE obj. for every http request
* client: a PERSISTENT (TCP) stream obj.
*
client.on('data', function() { });
**/
}
var client = new net.Socket();
// ref#1
client.connect(shared.tcp.port, shared.tcp.host, function() {
console.log('TCP conn. established to: ', shared.tcp.host, shared.tcp.port);
});
var nextId = 0;
// unique per http req.
/**
* [!] Do this ( once ) ( not for every request )
*/
client.on('data', function(data)
{
protocol.extractMessages(data, function(message) {
client.emit('message' + message.id, message.body);
// ref#3
});
});
client.on('close', function()
{
console.log('TCP conn. closed');
client.removeAllListeners();
})
client.on('error', function()
{
console.log('TCP conn. error', arguments);
// client.destroy(); // and reconnect here
});
tcpServer.js
var net = require('net');
var shared = require('./shared.js');
var protocol = new shared.protocol();
var server = net.createServer(handleConnection);
server.listen(shared.tcp, function() {
console.log('TCP server listening %s:%s', shared.tcp.host, shared.tcp.port);
});
// [!] CONNECTION handler ( ref#1 )
function handleConnection(client)
{
var this.dataBuffer = '';
// [!] DATA handler ( ref#2 )
client.on('data', function(data) {
protocol.extractMessages(data, function(message)
{
var requestId = message.id;
var body = message.body;
// Do whatever you want with 'body' here
/**
* And return back to 'client' with 'requestId' using same protocol again
* so the 'client' ( from httpServer.js ) can handle your response
*/
client.write( protocol.packMessage(requestId, body) );
});
});
}
Upvotes: 1
Reputation: 161
Can you instantiate a new client for each incoming request? This way the TCP connection for each request will be unique.
Upvotes: 0