I'm currently running into a problem you guys might be able to help me with..
I'm using websockets to connect to a custom server. Now i want to integrate a second Server IP if the first one isn't available.
How is it possible to detect, that the connection couldn't be made because the server isn't reachable? When I enter a wrong ws://url in my script, Chrome for example gives me the following error:
WebSocket connection to 'wss://1234/' failed: Error in connection establishment: net::ERR_NAME_NOT_RESOLVED
in Firefox it's something complete different. Do you guys of any method to catch this error with Javascript?
Basically when the ws:// url can't be reached, i want to change a variable with a different Server-IP and try it with this one again...
Thanks for your help!
It seems there's no way to catch the problem on instantiation, even though the magical JavaScript black box somehow seems to know the problem occurs on the new WebSocket.
To detect this error, use the following:
ws = new WebSocket(server);
ws.onerror = function (evt) {
if (ws.readyState == 3) {
//Connection closed.
}
}
thanks #orbitbot,
I'm using a framework called jwebsocket (jwebsocket.org). My Code is basically this:
serverstate = "0";
console.log(serverstate);
function logon() {
if(serverstate == "0") {
lURL = "wss://testurl-one:9797";
} else if (serverstate == "1") {
lURL = "wss://testurl-two:9797";
}
var gUsername = "user";
var lPassword = "pass";
console.log( "Connecting to " + lURL + " and console.logging in as '" + gUsername + "'..." );
var lRes = lWSC.logon( lURL, gUsername, lPassword, {
// OnOpen callback
OnOpen: function( aEvent ) {
console.log( "jWebSocket connection established." );
},
// OnMessage callback
OnMessage: function( aEvent, aToken ) {
var lDate = "";
if( aToken.date_val ) {
lDate = jws.tools.ISO2Date( aToken.date_val );
}
console.log( "jWebSocket '" + aToken.type + "' token received, full message: '" + aEvent.data + "' " + lDate + "" );
console.log(aToken);
}
},
// OnClose callback
OnClose: function( aEvent ) {
console.log( "Disconnected from Server" );
console.log("Using next server..");
serverstate = "1";
console.log(serverstate);
console.log("Trying to connect to next server");
logon();
},
// OnClose callback
OnError: function( aEvent ) {
console.log ("Some error appeared");
}
});
console.log( lWSC.resultToString( lRes ) );
}
Of course this would work so far. My Problem is that im using websockets to open a connection, get some information, and after that close the connection again.
since this code will always be fired if the server connection is closed (which in many cases i want to..) i can't use it like that...
any other ideas on this problem ?
I got it.. for everyone else who's interested:
When connection is made you receive a message from there server. So if the server is not available.. there'll be no message. So i just added a variable to the "OnMessage" Part.. and in the disconnect i check if a message was received. If not the server isn't there.. if yes, everything works fine..
Assuming your code is something like this,
var host = 'ws://a.real.websocket.url';
var socket = new WebSocket(host);
... you just need to surround the call to new WebSocket with a try/catch block, something like this
try {
var socket = new WebSocket(host);
} catch (e) {
// inspect e to understand why there was an error
// and connect to another url if necessary
}
That being said, it might be easier to work with a websockets library such as Socket.IO or SockJS (https://github.com/sockjs/sockjs-client), which then would change your reconnection code logic to whatever the libraries provide.
Related
I have a Tornado client application which runs fine at its current state: In a simplified version, it has a structure like the folllowing code piece:
function comms(callback, newSession, connection) {
if (newSession == true) {
connection = new WebSocket('ws://localhost:9022/id/01234');
connection.onopen = function () {
alert("connected");
connection.send('hello world');
};
}
connection.onerror = function (error) {
alert('WebSocket Error ' + error);
};
connection.onmessage = function (e) {
alert('>> message from Host: ' + e.data);
callback(e.data, connection);
}
}
I can connect, I can detect connection is on, I can send messages. I can receive messages. I can forward message via callback function and come back. No problem. All these are done via:
connection.onXXX event handler functions.
Now I want to send some unsolicited messages to server like the following:
function comms(callback, newSession, connection, request=false) {
if (newSession == true) {
connection = new WebSocket('ws://localhost:9022/id/01234');
connection.onopen = function () {
alert("connected");
connection.send('hello world');
};
}
connection.onerror = function (error) {
alert('WebSocket Error ' + error);
};
connection.onmessage = function (e) {
alert('>> message from Host: ' + e.data);
callback(e.data, connection);
}
if (request == true) {
connection.send("request_msg");
}
}
Although connection is open, I can not send such a request message. I receive:
"connection.send is not a function" error.
As I understand, somehow send request must be wrapped into a function, like other connection.onXXXX event handlers. But I do not have any such event or handler.
How can I send my message?
It would seem you would need to do this within an event.
UPDATED:
The onmessage event is what is fired on the server side, so any client processing can't be done in that event handler. I would suggest the client side functionality should be handled in a different function (not comms).
According to this reference tutorial (an-introduction-to-websockets), just call the send request from within the function from the client that requests the message.
Ie. as per the tutorials example, found here, the request is called when the form is submitted / send message button is pressed. This is all wrapped in the onload function.
So you need some client side event or loop that can call the socket connection(socket).send() function, simply passing in text should be sufficient.
Does this help at all or does your application in it's 'complex' state achieve this already?
I've got a Java web application deployed on a local GlassFish 4.1 server that implements WebSockets to inter-operate with the web client. I'm able to successfully execute client-to-server communication over the socket, but server-to-client communication doesn't work for some reason.
The Java code that sends messages to the client:
try
{
String msg = ServerClientInteropManager.toResponseJSON(response);
parentSession.getBasicRemote().sendText(msg);
FLAIRLogger.get().info("Sent response to client. Message: " + msg);
}
catch (IOException ex) {
FLAIRLogger.get().error("Couldn't send message to session " + parentSession.getid() + ". Exception - " + ex.getMessage());
}
The Javascript code:
pipeline_internal_onMessage = function(event)
{
var msg = JSON.parse(event.data);
console.log("Received message from server. Data: " + event.data);
};
function pipeline_init()
{
if (PIPELINE !== null || PIPELINE_CONNECTED === true)
{
console.log("Pipline already initialized");
return false;
}
else
{
var pipelineURI = "ws://" + document.location.host + document.location.pathname + "webranker";
console.log("Attempting to establish connection with WebSocket # " + pipelineURI);
if ('WebSocket' in window)
PIPELINE = new WebSocket(pipelineURI);
else if ('MozWebSocket' in window)
PIPELINE = new MozWebSocket(pipelineURI);
else
{
console.log("FATAL: No WebSockets support");
alert("This browser does not support WebSockets. Please upgrade to a newer version or switch to a browser that supports WebSockets.");
return false;
}
// the other event listeners get added here
PIPELINE.onMessage = pipeline_internal_onMessage;
PIPELINE_CONNECTED = true;
window.onbeforeunload = function() {
pipeline_deinit();
};
console.log("Pipeline initialized");
return true;
}
}
The onMessage function is never fired, even when the server successfully calls the sendText() method. Using the AsyncRemote yields the same results. The onError listeners on both ends don't report anything either. This is my first time working with sockets so I might be missing something elementary.
replace
PIPELINE.onMessage = pipeline_internal_onMessage
with
PIPELINE.onmessage = pipeline_internal_onMessage
Please refer here for more.
I am trying to create Server-Sent events on my Ruby Grape API.
The problem is that the connection seems to be closed really fast all the time, as I get Connection closed event all the time on test webpage.
The client connects to the server as I can see the method being called, but I would like to know why is the connection not constant and why I don't receive the data I send using the Thread.
Here is my Ruby code:
$connections = []
class EventsAPI < Sinantra::Base
def connections
$connections
end
get "/" do
content_type "text/event-stream"
stream(:keep_open) { |out|
puts "New connection"
out << "data: {}\n\n"
connections << out
}
end
post "/" do
data = "data\n\n"
connections.each { |out| out << data }
puts "sent\n"
end
end
Here is my Javascript:
var source = new EventSource('http://localhost:9292/events');
source.onmessage = function(e) {
console.log("New message: ", e.data);
showMessage(e.data);
};
source.onopen = function(e) {
// Connection was opened.
};
source.onerror = function(e) {
console.log("Source Error", e)
if (e.eventPhase == EventSource.CLOSED) {
console.log("Connection was closed");
// Connection was closed.
}
};
var showMessage = function(msg) {
var out = document.getElementById('stream');
var d = document.createElement('div')
var b = document.createElement('strong')
var now = new Date;
b.innerHTML = msg;
d.innerHTML = now.getHours() + ":" + now.getMinutes() + ":" +now.getSeconds() + " ";
d.appendChild(b);
out.appendChild(d);
};
EDIT: I got it working with the GET method (I changed the Grape::API to Sinatra::Base as Grape does not implement stream). I now receive data, but the connection is not kept alive and when I use the post method the data never reaches the browser.
Thank you in advance for your answers.
The JS code looks correct. My guess is that you should not start a new thread for your infinite loop. What will be happening is that the main thread will carry on executing, reach the end of its block, and close the http request. Your detached thread is then left writing to a non-existent out stream.
UPDATE in response to your EDIT: POST is not supported in SSE. Data can only be passed to an SSE process by using GET data or cookies.
I am new to node.js. How to detect client is disconnected from node.js server .
Here is my code:
var net = require('net');
var http = require('http');
var host = '192.168.1.77';
var port = 12345;//
var server = net.createServer(function (stream) {
stream.setEncoding('utf8');
stream.on('data', function (data) {
var comm = JSON.parse(data);
if (comm.action == "Join_Request" && comm.gameId =="game1") // join request getting from client
{
var reply0 = new Object();
reply0.message = "WaitRoom";
stream.write(JSON.stringify(reply0) + "\0");
}
});
stream.on('disconnect', function() {
});
stream.on('close', function () {
console.log("Close");
});
stream.on('error', function () {
console.log("Error");
});
});
server.listen(port,host);
How to know client side internet disconnection.
The best way to detect "dead sockets" is to send periodic application-level ping/keepalive messages. What that message looks like depends on the protocol you're using for communicating over the socket. Then it's just a matter of using a timer or other means of checking if you've received a "ping response" within a certain period of time after you sent the ping/keepalive message to the client.
On a semi-related note, it looks like you're using JSON messages for communication, but you're assuming a complete JSON string on every data event which is a bad assumption. Try using a delimiter (a newline is pretty common for something like this, and it makes debugging the communication more human-readable) instead.
Here is a simple example of how to achieve this:
var PING_TIMEOUT = 5000, // how long to wait for client to respond
WAIT_TIMEOUT = 5000; // duration of "silence" from client until a ping is sent
var server = net.createServer(function(stream) {
stream.setEncoding('utf8');
var buffer = '',
pingTimeout,
waitTimeout;
function send(obj) {
stream.write(JSON.stringify(obj) + '\n');
}
stream.on('data', function(data) {
// stop our timers if we've gotten any kind of data
// from the client, whether it's a ping response or
// not, we know their connection is still good.
clearTimeout(waitTimeout);
clearTimeout(pingTimeout);
buffer += data;
var idx;
// because `data` can be a chunk of any size, we could
// have multiple messages in our buffer, so we check
// for that here ...
while (~(idx = buffer.indexOf('\n'))) {
try {
var comm = JSON.parse(buffer.substring(0, idx));
// join request getting from client
if (comm.action === "Join_Request" && comm.gameId === "game1") {
send({ message: 'WaitRoom' });
}
} catch (ex) {
// some error occurred, probably from trying to parse invalid JSON
}
// update our buffer
buffer = buffer.substring(idx + 1);
}
// we wait for more data, if we don't see anything in
// WAIT_TIMEOUT milliseconds, we send a ping message
waitTimeout = setTimeout(function() {
send({ message: 'Ping' });
// we sent a ping, now we wait for a ping response
pingTimeout = setTimeout(function() {
// if we've gotten here, we are assuming the
// connection is dead because the client did not
// at least respond to our ping message
stream.destroy(); // or stream.end();
}, PING_TIMEOUT);
}, WAIT_TIMEOUT);
});
// other event handlers and logic ...
});
You could also just have one interval instead of two timers that checks a "last data received" timestamp against the current timestamp and if it exceeds some length of time and we have sent a ping message recently, then you assume the socket/connection is dead. You could also instead send more than one ping message and if after n ping messages are sent and no response is received, close the connection at that point (this is basically what OpenSSH does).
There are many ways to go about it. However you may also think about doing the same on the client side, so that you know the server didn't lose its connection either.
I am bit new in CGI programming, and I trying to make an online chat API but face not few troubles:
I was looking online for solution and found Websocket for client (js) and HTTP::Daemon for perl, but I have no idea where to start to make the server listen for the connections from the browser.
Here is my JavaScript code:
ws = new WebSocket('ws://www.crazygao.com:3000'); // test
ws.onopen = function() {
alert('Connection is established!'); // test
};
ws.onclose = function() {
alert('Connection is closed');
};
ws.onmessage = function(e) {
var message = e.data;
//alert('Got new message: ' + message);
};
ws.onerror = function(e) {
//var message = e.data;
alert('Error: ' + e);
};
Here is my Perl script test code:
use HTTP::Daemon;
use HTTP::Status;
my $d = HTTP::Daemon->new(
LocalAddr => 'www.crazygao.com',
LocalPort => 3000
) || die; print "Please contact me at: <URL:", $d->url, ">\n";
while(my $c = $d->accept) {
$c->send_response("1"); # test
while (my $r = $c->get_request) {
if ($r->method eq 'GET') {
$c->send_response("...");
}
}
$c->close;
undef($c);
}
When the page loads, the connection closing immediately, and in Chrome console window I see the following error:
WebSocket connection to 'ws://198.38.89.14:3000/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I run the perl script manually (using simple call to http://example.com/cgi-bin/xxx.cgi) and then when I refresh the page I get:
WebSocket connection to 'ws://198.38.89.14:3000/' failed: Error during WebSocket handshake: Unexpected response code: 200
I understand that the server normally returns 200 when OK, but Websocket is waiting for 101 code as "OK".
My question is, if so, how can I achieve this?
I know this is old and I got here because I was looking for an answer myself. I ended up finding the answer myself by using Net::WebSocket::Server.
http://search.cpan.org/~topaz/Net-WebSocket-Server-0.003004/lib/Net/WebSocket/Server.pm for more details on how to use the module and example.
Basically, you'll have this perl code to match your javascript (copied and modified from the CPAN page of Net::WebSocket::Server):
use Net::WebSocket::Server;
my $origin = 'http://www.crazygao.com';
Net::WebSocket::Server->new(
listen => 3000,
on_connect => sub {
my ($serv, $conn) = #_;
$conn->on(
handshake => sub {
my ($conn, $handshake) = #_;
$conn->disconnect() unless $handshake->req->origin eq $origin;
},
utf8 => sub {
my ($conn, $msg) = #_;
$_->send_utf8($msg) for $conn->server->connections;
},
binary => sub {
my ($conn, $msg) = #_;
$_->send_binary($msg) for $conn->server->connections;
},
);
},
)->start;