I have a NodeJS server running on Heroku (free version). The server accepts a HTTP POST from a client (passing a parameter) and does a web request (using the parameter) in a headless browser. The headless browser is called HorsemanJS. "Horseman is a Node.js module that makes using PhantomJS a pleasure. It has a straight-forward chainable API, understandable control-flow, support for multiple tabs, and built-in jQuery."
When I send a request (actually for loop of 20 requests) from a client (my computer) to the server, the server code works correctly (does 20 HorsemanJS web requests), and returns the expected values. Then, it waits for the next connection. This is all good.
The problem is, when I try to connect to the server with two different clients (my computer and phone) at the same time, it crashes. I can reboot the server and return to using one client successfully. How can I make it handle multiple clients?
Error when crashed:
child_process.js:788
child.stdout.addListener('data', function(chunk) {
^
TypeError: Cannot read property 'addListener' of undefined
at Object.exports.execFile (child_process.js:788:15)
at exports.exec (child_process.js:649:18)
at Socket.<anonymous> (/app/node_modules/node-horseman/node_modules/node-phantom-simple/node-phantom-simple.js:237:7)
at Socket.g (events.js:199:16)
at Socket.emit (events.js:107:17)
at readableAddChunk (_stream_readable.js:163:16)
at Socket.Readable.push (_stream_readable.js:126:10)
at Pipe.onread (net.js:538:20)
Extract from my server code:
var express = require('express');
var app = express();
var Horseman = require('node-horseman');
app.set('port', (process.env.PORT || 5000));
var printMessage = function() { console.log("Node app running on " + app.get('port')); };
var getAbc = function(response, input)
{
var horseman = new Horseman();
horseman
.userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0") // building web browser
.open('http://www.stackoverflow.com')
.html()
.then(function (result) {
var toReturn = ijk(result));
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end(toReturn);
}).close();
}
var handleXyz = function(request, response)
{
getAbc(response, request.query.input);
}
app.listen(app.get('port'), printMessage);
app.post('/xyz', handleXyz);
I tried moving .close inside .then, and also before .then. The code still worked for a single client, but not multiple.
I suspect the problem is that one client is closes a PhantomJS instance while/before the client tries to use it.
Putting horseman.close() inside of the finally may not give it enough time to actually close our the phantomJS process completely. Try changing the finally into a .then(), and return horseman.close().
Related
I have been trying to setup a wss server using nodejs, and have encountered a problem when trying to connect to it using chrome. The problem still occurs with all extensions disabled and in an incognito window so I've ruled that out as the problem.
When trying to connect using chrome, I get the error:
WebSocket connection to 'wss://www.domain-name.com/' failed:
with no reason given. On the server, socket.on('close') is called immediately with description "Connection dropped by remote peer" The close event has wasClean = false. This error does not occur when connecting from safari and Firefox so I'm not really sure where to look to see what's causing it. It's running on AWS Lightsail, and through an Apache proxy server.
The client code:
var socket = new WebSocket("wss://www.domain-name.com", 'JSON')
socket.onopen = function (event) {
console.log('open');
socket.send('socket opened')};
socket.onclose = function (event) {
console.log(event)};
socket.onmessage = function(message) {
console.log('receiving message from server...')};
And the server code:
const WebSocketServer = require('websocket').server;
app = express()
var server = app.listen(3000, () => {
console.log('Server started');
});
app.use(express.static('public'));
var wsServer = new WebSocketServer({
httpServer: server
});
wsServer.on('request', function(request){
console.log('New connection');
var connection = request.accept(null, request.origin);
connection.send('welcome from server...');
connection.on('message', function(message){
console.log(message)};
connection.on('close', function(reasonCode, description) {
console.log('disconnecting', reasonCode, description);
});
});
I also got the same error before switching to a secure WebSocket server. Any help would be appreciated, I've run out of places to look and ways to try and get more information to help out what the problem is.
EDIT: it seems to work on chrome on my phone, but not on chrome on my friends phone?
The problem was not specifying the protocol when accepting the connection. After about 20 hours working on the same bug and implementing an SSL certificate to get it to work, I changed:
request.accept(null, request.origin);
to:
request.accept('json', request.origin);
For some reason the chrome gives a really unhelpful error message. Microsoft edge the same error occurs, but gives a much more helpful error message so I could work out what was going on.
In my case, this was caused by passing an unused options value as the third parameter to the WebSocket constructor. The options parameter is supported by Node.js's ws module but not by browsers; however, instead of displaying a clean error message, Chrome closed the connection without a good description.
I am trying to setup a communication between a python script (that will do a lot of computation on data that cannot be done in javascript and send send that data as a json) and a javascript client.
I have the following code for my python server:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 9888 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
#Function for handling connections. This will be used to create threads
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = conn.recv(1024)
reply = 'OK...' + data
if not data:
break
conn.sendall(reply)
#came out of loop
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
start_new_thread(clientthread ,(conn,))
s.close()
And the following code for my javascript client:
var connection = new WebSocket('ws://127.0.0.1:8999');
connection.onopen = function () {
connection.send('Hello'); // Send the message to the server
};
I get the following error from my javascript client:
Error during WebSocket handshake: net::ERR_INVALID_HTTP_RESPONSE
And the following output from my python server
Socket created
Socket bind complete
Socket now listening
Connected with 127.0.0.1:53956
Unhandled exception in thread started by <function clientthread at 0x10abac578>
Traceback (most recent call last):
File "server.py", line 71, in clientthread
data = conn.recv(1024)
socket.error: [Errno 54] Connection reset by peer
Would anyone know what is wrong?
Edit: forgot to mention that I have seen this SO Post before, but my problem is not the same, or rather should I say that the error encountered by OP is not the same as mine.
A WebSocket is a not the same as a plain TCP socket you create. WebSocket is a protocol on top of TCP instead which starts with a HTTP handshake and then continues with a framing based protocol. If you want to implement a WebSocket server in Python you need to implement this protocol as specified in RFC 6455 or use existing WebSocket libraries.
An example server-side python code using WebSocket is:
import asyncio
import websockets
async def handle_message(message):
print(message)
async def consumer_handler(websocket, path):
while True:
message = await websocket.recv()
await handle_message(message)
start_server = websockets.serve(consumer_handler, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
I would like to fiddle with websockets a bit. I installed a Ruby gem called "websocket-ruby" (https://github.com/imanel/websocket-ruby) I started a pry / IRB session and typed:
require "websocket"
#handshake = WebSocket::Handshake::Server.new(:host => "localhost", :port => 8080,:secure=>true)
This starts a websocket server as far as I know. Then I opened in my browser the Javascript HTML page which attempt to connect to the server:
<!doctype html>
<html lang="en">
<head>
<title>Websocket Client</title>
</head>
<body>
<script>
var exampleSocket = new WebSocket("wss://localhost:8080");
exampleSocket.onopen = function (event) {
exampleSocket.send("Can you hear me?");
};
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
</script>
</body>
</html>
But it says in the console log:
failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I tried different ports both in server and in the client respectively: 8081, 12345, but I always get this error message.
I have some idea about websocket and javascript, but not websocket-ruby.
I hope it will helpful you.
In nodejs.. server.js file, write below code
var WebSocketServer = require("ws").Server;
var wss = new WebSocketServer({port:8100});
console.log("websocket Server is Running...");
wss.on('connection', function connection(ws) {
// Store the remote systems IP address as "remoteIp".
var remoteIp = ws.upgradeReq.connection.remoteAddress;
// Print a log with the IP of the client that connected.
console.log('Connection received: ', remoteIp);
// Add a listener which listens for the "message" event.
// When a "message" event is received, take the contents
// of the message and pass it to the broadcast() function.
ws.on('message', wss.broadcast);
});
wss.broadcast = function(msg) {
wss.clients.forEach(function each(client) {
client.send(msg);
})
};
In javascript...
var SERVER_URL = 'ws://localhost:8100';
//instead of localhost you can also use IP address of your system
var ws;
function connect() {
alert('connect');
ws = new WebSocket(SERVER_URL, []);
// Set the function to be called when a message is received.
ws.onmessage = handleMessageReceived;
// Set the function to be called when we have connected to the server.
ws.onopen = handleConnected;
// Set the function to be called when an error occurs.
ws.onerror = handleError;
}
function handleMessageReceived(data) {
// Simply call logMessage(), passing the received data.
logMessage(data.data);
}
function handleConnected(data) {
// Create a log message which explains what has happened and includes
// the url we have connected too.
var logMsg = 'Connected to server: ' + data.target.url;
// Add the message to the log.
logMessage(logMsg)
}
function handleError(err) {
// Print the error to the console so we can debug it.
console.log("Error: ", err);
}
function logMessage(msg) {
// with the new message.
console.log(msg);
}
/** This is the scope function that is called when a users hits send. */
function sendMessage{
ws.send(msg);
};
connect();
in html use one button to send message to websocket server
<button onclick="sendMessage('Hi Websocket')">send message</button>
To the best of my knowledge, the Ruby code you presented does not start a Websocket server... what it does is initiate a server-side parser.
To start a server you need to use an actual websocket server.
ActionCable (with Rails) uses the websocket-ruby library to parse websocket events and it uses nio4r to operate the actual server.
Faye have a similar solution and em-websockets use the websocket-ruby gem with EventMachine.
Other Ruby Websocket servers include Iodine, which uses the C library facil.io. Iodine is used by the framework plezi as well as independently.
Since you were trying to run an echo server, here's a quick example using the Plezi framework (you can use it as middleware in Sinatra or Rails)...
...place the following in a config.ru file:
require 'plezi'
class WebsocketSample
# HTTP index
def index
'Hello World!'
end
# called when Websocket data is recieved
#
# data is a string that contains binary or UTF8 (message dependent) data.
def on_message(data)
puts "Websocket got: #{data}"
write data
end
end
Plezi.route '/', WebsocketSample
run Plezi.app
To run the server, call (ignore the $ sign, it marks this code as terminal code):
$ iodine
notice: Iodine requires a BSD / Unix / Linux machine, such as macOS, Ubuntu, etc'. It won't work on windows.
I am using Aurora 17, Chrome 22 and Firefox 16 and I am trying to create a simple chat app. I am using Node 0.8.9.
Firefox is getting the error that it cannot connect giving the error
Firefox can't establish a connection to the server at ws://localhost/.
I also tried it with the port and it have the same message
Firefox can't establish a connection to the server at ws://localhost:4444/.
Here is my code:
Server Code:
var http = require('http');
var net = require('net');
function onRequest(req, res) {
// Does enough to render a page and javascript
}
http.createServer(onRequest).listen(4444);
var socket = new net.Socket();
socket.connect(4444, "localhost", function(){
console.log("Socket Connected");
});
socket.on("message", function(message){
console.log(message);
});
Client Code:
var WebSocket = window.WebSocket || window.MozWebSocket;
var connection = new WebSocket('ws://localhost:4444');
connection.onopen = function() {
// Never runs
alert("This never runs :(")
}
connection.onerror = function(error) {
// Always runs here
console.log(error)
}
I get an output that the Socket is connect from the log statement on the server but Firefox cannot connect to the socket.
On Chrome, there is no error but the "onopen" is never fired. Using connection.send("a message") does not send anything to the server and returns false.
You're creating an ordinary TCP client socket in your server code and connecting it to your HTTP server. That's not at all the same thing as creating a WebSocket server that a browser can connect to. Use a library designed for the purpose (socket.io is very commonly used, since it can fall back to alternate transports when a browser doesn't support WebSockets).
I've been having a heck of a time figuring out how to use Node.js (v0.3.8) to securely connect to an HTTP server. I have the following code:
var http = require("http");
var client = http.createClient(443, host, /* secure= */ true);
var request = client.request("GET", relativeUrl, { host: host });
When I run it, I get:
node.js:116
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Parse Error
at Client.onData [as ondata] (http.js:1287:27)
at Client._onReadable (net.js:648:27)
at IOWatcher.onReadable [as callback] (net.js:156:10)
I've been Googling for answers for the past half hour, and have read the documentation at http://nodejs.org/ . What am I missing?
It turns out I was using an old version of the Node documentation, which didn't include a reference to the https module. Referring to the current docs, I found http://nodejs.org/docs/latest/api/https.html#https_https_get_options_callback, which provides an example:
https.get({ host: 'encrypted.google.com', path: '/' }, function (res) { … });
If you are using node.js as a client you should be able to simply substitute http for https.
That is according to the following website
https://github.com/danwrong/Restler/
"Transparently handle SSL (just specify https in the URL)"