I'm programming a simple web socket chat application. When I open the socket, I send a message to join the room with a name and the web socket returns the updated room object showing the current users names.
I'm trying to send the updated room with user names to all open connections, so if I open 2 browser tabs, I should see the users added by one tab reflected in the other, however I don't see that. When debugging on the session.getOpenSessions() I only ever see a single session. I would expect to also see the connection of the other browser tab.
JS
window.onload = function() {
var socket = new WebSocket('ws://localhost:8080/chat/roomName');
socket.onmessage = function(event) {
document.getElementById('message').message.innerHTML = event.data;
};
socket.onopen = function(event) {
socket.send('{"command":"join", "value":"MyName"}');
};
}
Web socket code
#OnOpen
public void onOpen(Session session, #PathParam("roomName") String roomName) throws IOException, EncodeException {
currentSession = session;
session.getBasicRemote().sendObject(getRoom(roomName));
}
On load
for (Session session: currentSession.getOpenSessions()){
try {
if(session.isOpen() && session.getUserProperties().get("roomName").equals(room.getRoomName())){
session.getBasicRemote().sendObject(room);
}
} catch (Exception e){
e.printStackTrace();
}
}
By default websocket creates a new server (Endpoint) for every request from client.so when you are doing session.getOpenSessions() returns the same session.
make the server endpoint singleton .link
Related
With the following code i open a stream connection to the Binance crypto exchange:
let adress = 'wss://stream.binance.com:9443/ws/btcusdt#kline_1h';
const ws = new WebSocket(adress);
If i make this call for different crypto currencys then i have later a few streams open, i want to know how can i check the current open streams, is there something like a function or parameter where i can see for which currencys i have a open stream running?
because i also have the problem that it looks like streams are stopping sometimes and i dont have a good solution for checking which streams have stop and how to receonnect them. My idea is now to first find a way how to check which streams are running and then maybe if one streams is stop i will just send the connection request again.
In javascript there is a websocket events thing, so all you need is to
ws.onclose = function(event) {
ws = new WebSocket(adress);
//just reopen it
};
Or, for more safety, you can
ws.onclose = function(event) {
if (event.wasClean) {
ws = new WebSocket(adress);
} else {
console.log('Connection error!');
//or whatever u want
}
};
Sorry for this stupid styling, I'm newbie there
If you have your ws variable, then checking whether the websocket is open and alive is done with
if(ws && ws.readyState === 1){
// is opened
}
For other states of the websocket, see the docs.
If you want to receive push messages from the server, you need to keep the ws connection open. If not, you can close the ws after a query and reopen it then for another query. You should wait for the closed state ws.readyState === 3 before reopening.
If you need to keep all ws connections open, then you need a list of ws Objects. You push new objects to the list:
let ws_list = [] // global list of ws objects
let create_connection = function(url){
try{
ws_list.push(new WebSocket(url));
} catch(err){
console.log(err, url);
}
}
let do_something = function(){
for(let ws of ws_list){
// do something with the ws object
}
}
I am developing websocket server with netty frame work version 4.1.6.
I am using the sample code from netty example site
This is my server source code:
public class WebSocketServer
{
static final int PORT = 4466;
public static void main(String[] args)
{
final SslContext sslCtx;
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new WebSocketServerInitializer(sslCtx));
Channel ch = b.bind(PORT).sync().channel();
System.out.println("Open your web browser and navigate to " +
"http://127.0.0.1:" + PORT + '/');
ch.closeFuture().sync();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
An WebSocketServerInitializer source code:
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel>
{
private static final String WEBSOCKET_PATH = "/websocket";
private final SslContext sslCtx;
public WebSocketServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WebSocketServerCompressionHandler());
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
// pipeline.addLast(new WebSocketIndexPageHandler(WEBSOCKET_PATH));
pipeline.addLast(new WebSocketFrameHandler());
}
}
This is my Html code:
<html>
<head>
<script type="text/javascript">
// Let us open a web socket
var ws = null;
function WebSocketTest()
{
if ("WebSocket" in window)
{
alert("WebSocket is supported by your Browser!");
// Let us open a web socket
ws = new WebSocket("wss://localhost:4466/websocket");
ws.onopen = function()
{
// Web Socket is connected, send data using send()
ws.send("Message to send");
alert("Message is sent...");
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
alert(received_msg);
//alert("Message is received...");
};
ws.onclose = function()
{
// websocket is closed.
alert("Connection is closed...");
};
window.onbeforeunload = function(event) {
socket.close();
};
}
else
{
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}
}
</script>
</head>
<body>
<div id="sse">
Run WebSocket
</div>
</body>
</html>
I browse the page using Chrome browser and got the following message when I click on the link in the web page.
WebSocket connection to 'wss://localhost:4466/websocket' failed: Error in connection establishment: net::ERR_INSECURE_RESPONSE
According to some discussions here, and the netty websocket sample code, wss must be forwarded by HTTPS. However, when I change the following javascript statement in my web page:
ws = new WebSocket("wss://localhost:4466/websocket");
to
ws = new WebSocket("wss://echo.websocket.org");
It works fine. It make me confusing, Why the site echo.websocket.org can working without https? Why my server cannot? are there something missing in my server source code?
PS: the echo.websocket.org example found in the following url:
http://jsbin.com/muqamiqimu/edit?js,console
Your browser is failing to connect to your websocket server, because it detected it is insecure.
This happens because when the browser tries to connect to your server, it will check the SSL certificate. This certificate is basically a proof that says your server is claiming to be the authoritative server for localhost.
Your server claims this by its certificate, what in your case is signed by itself, that's basically the SelfSignedCertificate class, and it's claiming to be "example.com".
This creates 2 issues:
Your browser connects to localhost, but instead of getting a certificate for localhost, it gets 1 for example.com
Your browser does not trust the signer of the certificate to have the authority to make certificates, causing it to be rejected.
There are multiple ways to solve this:
Getting a valid certificate and hosting your application on a server
This would be the recommended solution for production, depending where you get your valid certificate, it may or may not cost money.
Bypass the certificate warning
By manually going to http://localhost:4466/ you can skip past the certificate warning, and basically this adds a 1 time exception for the certificate rule, till you restart your browser
Configuring google chrome to accept invalid certificates for localhost
While this can be insecure (but not as insecure as turning off all certificate validation), it can be a great way to test ssl on development machines.
You can turn ssl validation of for localhost by going to chrome://flags/#allow-insecure-localhost and turning that option on. Notice that you might be required to set the domain of your certificate to localhost when using this option by calling the new SelfSignedCertificate("localhost"); contructor.
I'm attempting to write a C# WebSocket server for an application that interacts upon browser input.
This is the code:
class Program {
static void Main(string[] args) {
var listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 42001);
listener.Start();
using(var client = listener.AcceptTcpClient())
using(var stream = client.GetStream())
using(var reader = new StreamReader(stream))
using(var writer = new StreamWriter(stream)) {
while (!reader.EndOfStream) {
String line = reader.ReadLine();
if (new Regex("^GET").IsMatch(line)) {
line = reader.ReadLine();
if (new Regex("^Sec-WebSocket-Key: ").IsMatch(line)) {
String key = new Regex("(^Sec-WebSocket-Key\\: |\\r\\n)").Replace(line, "");
key = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")));
writer.WriteLine("HTTP/1.1 101 Switching Protocols");
writer.WriteLine("Upgrade: websocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("Sec-WebSocket-Accept: " + key);
writer.WriteLine("Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits");
writer.WriteLine("WebSocket-Origin: http://127.0.0.1");
writer.WriteLine("WebSocket-Location: ws://localhost:42001/websocket");
writer.WriteLine("");
}
}
}
}
listener.Stop();
}
}
... and:
var ws = new WebSocket('ws://localhost:42001/websocket');
ws.onopen = function() {
console.log('connected');
};
ws.onmessage = function(e) {
console.log(e.data);
};
ws.onerror = function(e) {
console.log(e);
};
ws.onclose = function() {
console.log("closed");
};
On execution, the TPCListener successfully accepts the TCPClient and reads the incoming HTTP request. It parses the Key, generates the correct Accept token, but the JS - window native - WebSocket seems to have gone flat out bonkers: it does not answer no matter what it receives.
I would expect it throwing an error upon sending a HTTP/1.1 400 Bad Request, but nothing at all happens. It just goes mute.
Checking out Chrome Dev Tools' Networking tab, I do only see the websocket outgoing GET request, but no incoming packets - is that supposed to happen?
If I forcefully close the application, WebSocket throws this exception:
WebSocket connection to 'ws://localhost:42001/websocket' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET.
What am I missing here? Thank you all in advance.
Also, I'm not using Net.WebSockets because it is available since .NET 4.5, and my application targets systems from Windows 7 to the current build of Windows 10.
well... how far does your C# code get? My first bet would be on buffering - you don't flush the writer or stream, so I would expect them to be holding onto data while stuck in the top of the while loop, but frankly it shouldn't be a while loop in the first place - you only get one handshake per socket, not many. You could try adding flushes after the blank line, and you should make sure the Socket itself has buffering disabled (NoDelay = true;) - but: fundamentally this isn't a good way to write a web-socket server. Apart from anything else, the data will cease to be text if the handshake succeeds, so having a TextReader is a very bad thing. Frankly, you should be dealing with raw Socket / byte[] data here, IMO (having implemented this very thing several times).
I have recently developed a web app using PeerJS, and am trying to add reconnect functionality.
Basically, my app works by someone creating a server that clients then connect to. The server person can control what the hosts are doing but its basic two way communication.
If a client disconnects they simply reconnect and it works normally. However if the server user refreshes the page, or their computer crashes then they need to be able to re-establish control over the clients.
The start of this is by regaining the original connection ID and peer api ID, which is fine and easy as they are stored in a database and assigned a unique ID the server user can use to query them. Then to enable the client to reconnect I do this upon close:
// connection is closed by the host involuntarily...
conn.on('close', function() {
// if the clients connection closes set up a reconnect request loop - when the host takes back control
// the client will auto reconnect...
connected = false;
conn = null;
var reconnect_timer = setInterval(function () {
console.log('reconnecting...'); // make a fancy animation here...
conn = peer.connect(connectionid, {metadata: JSON.stringify({'type':'hello','username':username})});
// upon connection
conn.on('open', function() { // if this fails need to provide an error message... DO THIS SOON
// run the connect function...
connected = true;
connect(conn);
});
// didnt connect yet
conn.on('error', function(err) {
connected = false;
});
if(connected === true) {
clearInterval(reconnect_timer);
}
}, 1000);
});
This appears to work, as on the server end the client looks like they have reconnected - the connect function has fired etc. However messages cant be sent between, and the client console says:
Error: Connection is not open. You should listen for the `open` event before sending messages.(…)
Where the 'open' event is shown as having been listened to above...
I hope this is clear - any help is appreciated :)
So in the end to create an auto reconnect script, I simply dealt with the client end of things, ensuring the server was set to the same api_key (for cloudservers) and key:
peer = new Peer(return_array.host_id, {key: return_array.api_key});
and then having the client, upon connection closing:
// connection is closed by the host involuntarily...
conn.on('close', function() {
// if the clients connection closes set up a reconnect request loop - when the host takes back control
// the client will auto reconnect...
peer.destroy(); // destroy the link
connected = false; // set the connected flag to false
conn = null; // destroy the conn
peer = null; // destroy the peer
// set a variable which means function calls to launchPeer will not overlap
var run_next = true;
// periodically attempt to reconnect
reconnect_timer = setInterval(function() {
if(connected===false && run_next===true) {
run_next = false; // stop this bit rerunning before launchPeer has finished...
if(launchPeer(false)===true) {
clearInterval(reconnect_timer);
} else run_next == true;
}
}, 1000);
});
Where launch peer will attempt to launch a new peer. To ensure continuity the new id from the client replaces the old id from the client and everything is a smooth takeover. The hardest part in the end was having the "setInterval" only fire once which is achieved (badly...) through use of boolean flags.
Thanks to anybody who read and thought how they could help :)
I am trying to implement a channel with my back-end server, which is running on the Google App Engine (Python), and I am unsure how to write the front end code for Chrome. I found some code, but am unable to test as I am waiting for the back-end code to be written by my partner. I am wondering if I am implementing this correctly.
I also do not understand how the code is triggered? What triggers this channel to be created?
//The code I found which is placed in background.html:
chrome.extension.onRequest.addListener (function(request, sender, sendResponse) {
var channel = new goog.appengine.Channel(channelToken);
var socket = channel.open()
socket.onopen = function() {
// Do stuff right after opening a channel
}
socket.onmessage = function(evt) {
// Do more cool stuff when a channel message comes in
}
});
Your code as written will open a channel whenever the background page receives a request from another part of your extension (e.g, a content script).
You probably want to open the channel as soon as the extension loads, and only then. To do this, just open the socket in your background.html JS, which runs on page load.
For example:
var channel = new goog.appengine.Channel(channelToken);
var socket = channel.open()
socket.onopen = function() {
// Do stuff right after opening a channel
}
socket.onmessage = function(evt) {
// Do more cool stuff when a channel message comes in
}
(Without the onRequest.addListener() wrapper)