I am trying to setup a signalR system.
I have the sample code working, using two browsers and the same hub. messages are sent and received.
Now, when I created a different page, and try to send messages to the hub, it appears to be kinda working, meaning it doesn't blow up, but nothing gets transmitted to the other clients.
I thought I was accessing the same message hub, from all the clients, but maybe I am missing something.
Is it possible to connect different web sites to the same message hub?
Begin Edit
As requested.... here is the code i am using on my second client...
var connection = $.hubConnection('http://xxxxxxxxx.azurewebsites.net/');
var contosoChatHubProxy = connection.createHubProxy('MessagePump');
// contosoChatHubProxy.on('Send', function (name, message) {console.log(name + ' ' + message);});
$.connection.hub.start()
.done(function () {
console.log('Now connected, connection ID=' + $.connection.hub.id); // returns an ID
// $.connection.hub.send('testing', 'this is a test from the client');
// contosoChatHubProxy.send("testing");
// contosoChatHubProxy.invoke('testing', 'this is a test for the client 1');
// contosoChatHubProxy.invoke('say', 'this is a test for the client 2');
// contosoChatHubProxy.invoke('Send', 'This is a test for client 3');
// $.connection.hub.send('testing', 'this is a test from the client 4');
contosoChatHubProxy.invoke('messagePump', 'user', 'this is a test message for 5');
})
.fail(function(){ console.log('Could not Connect!'); });
This is what i am seeing in firebug
From what i can make of the code, the proxy appears to be loading locally, and not even seeing the remote system hub...
My console application(s) that only connect to the remote system hub are able to send and receive messages.
btw - i have tried upper can lower case (MessagePump, messagePump)
but it has not changed the result.
var connection = $.hubConnection('http://xxxxxxxxx.azurewebsites.net/');
You are trying to connect a different website. This http://xxxxxxxxx.azurewebsites.net/ should let cross domain requests.Otherwise you can't connect. If you can manage http://xxxxxxxxx.azurewebsites.net/, you should configure signalr like:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Branch the pipeline here for requests that start with "/signalr"
app.Map("/signalr", map =>
{
// Setup the CORS middleware to run before SignalR.
// By default this will allow all origins. You can
// configure the set of origins and/or http verbs by
// providing a cors options with a different policy.
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
// You can enable JSONP by uncommenting line below.
// JSONP requests are insecure but some older browsers (and some
// versions of IE) require JSONP to work cross domain
// EnableJSONP = true
};
// Run the SignalR pipeline. We're not using MapSignalR
// since this branch already runs under the "/signalr"
// path.
map.RunSignalR(hubConfiguration);
});
}
}
Related
i'd like to ask some question about how to close a websocket client when offline/switched network.
when i try to close the socket for the 2 case in chrome, after i call websocket.close, i cannot recieve onclose event for a long time (around 60s), then i can recieve it finally.
after i check the readystate, i found that in the coming 60s, the state is 2(CLOSEING), not turned to 3(CLOSED).
so i'd like to know is there any steps i missed when i call websocket.close() in offline/switched network condition. while it runs well when the network is normal.
what's your back-end framework?
If you try to handle client's network that suddenly turned offline, there're two way you can try to close websocket from client as follows.
Kindly refer to source code here.
Using the js offline event handle
If we would like to detect if the user went offline we simply add websocket close function into offline event function.
front-end
function closeWebSocket() {
websocket.close();
}
$(window).on('beforeunload offline', event => {
closeWebSocket();
});
back-end (WebSocketServer)
#OnClose
public void onClose(Session session) {
CURRENT_CLIENTS.remove(session.getId());
}
Using Ping interval on the client-side and decrease the websocket timeout on server-side
If websocket server doesn't receive any message in specific time, it will lead to a timeout. So we can use this mechanism to decrease the timeout to close session if the client doesn't send any ping due to offline.
front-end
// send ping to server every 3 seconds
const keepAlive = function (timeout = 20000) {
if (websocket.readyState === websocket.OPEN) {
websocket.send('ping');
}
setTimeout(keepAlive, timeout);
};
back-end (WebSocketConfig)
#Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxSessionIdleTimeout(5000L);
return container;
}
In my code I am trying to send a POST request to the IFTTT service webhooks (maker).
I'm using a couple of libraries, mainly WiFi101
I am using an Arduino MKR1000.
I have updated the firmware, and added a certificate for https://maker.ifttt.com:443.
When in the following code I call sslClient.connect(host, 443); It fails to make the connection. I have tried bypassing this and just trying to print data to the host, however this also didn't work.
It takes about 10-20 seconds for the function to return as false, if I change the host to an incorrect variable, then it returns as false immediately. I'm assuming this is a good sign since the arduino is trying to connect?
wifiSetup() Runs well, connection is established reasonably quickly.
The code I am refering to is below:
Globally defined
//WiFi router setup
char ssid[] = "-----"; //network SSID (aka WiFi name)
char pass[] = "-----"; //network password
int status = WL_IDLE_STATUS;
const char* host = "https://maker.ifttt.com";
WiFiSSLClient sslClient;
Wifi setup procedure: This runs without problems
void wifiSetup() {
// Check for the presence of the shield
Serial.print("WiFi101 shield: ");
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("NOT PRESENT");
return; // don't continue
}
Serial.println("DETECTED");
// attempt to connect to Wifi network:
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to Network named: ");
Serial.println(ssid); // print the network name (SSID);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
printWifiStatus(); // you're connected now, so print out the status
}
The code below is the one causing problems
void sendMessage() {
if (sslClient.connect(host, 443)) {
//change this to your Maker setting from https://ifttt.com/services/maker/settings
String data = "randomdata";
sslClient.println("POST /trigger/tank_empty/with/key/bxa");
sslClient.println("Host: https://maker.ifttt.com");
sslClient.println("Content-Type: application/json");
sslClient.print("Content-Length: ");
sslClient.println(data.length());
sslClient.println();
sslClient.print(data);
sslClient.stop();
Serial.println("IFTTT request Sucessful");
}
else {
Serial.println("IFTTT request failed");
}
delay(20000000);
}
Does anyone have any solutions, or things to troubleshoot?
Thanks for your help all,
Let me know if you need any extra information.
https://maker.ifttt.com is not a valid host. A valid host is either an IP address or a domain. https:// is not a part of the domain, but an URL.
You are also missing the HTTP protocol version (HTTP/1.1), which could potentially cause problems.
const char* host = "maker.ifttt.com";
sslClient.println("POST /trigger/tank_empty/with/key/bxa HTTP/1.1");
sslClient.print("Host: ");
sslClient.println(host); // non hardcoded host header
sslClient.println("Content-Type: application/json");
sslClient.print("Content-Length: ");
sslClient.println(data.length());
sslClient.println();
sslClient.print(data);
sslClient.stop();
My problem is that the current solution I have for sending a specific socket using the library "ws" with node.js is not good enough.
The reason is because if I connect with multiple tabs to the websocket server with the same userid which is defined on the client-side, it will only refer to the latest connection with the userid specified.
This is my code:
// Server libraries and configuration
var server = require("ws").Server;
var s = new server({ port: 5001});
// An array which I keep all websockets clients
var search = {};
s.on("connection", function(ws, req) {
ws.on("message", function(message){
// Here the server process the user information given from the client
message = JSON.parse(message);
if(message.type == "userinfo"){
ws.personName = message.data;
ws.id = message.id;
// Defining variable pointing to the unique socket
search[ws.id] = ws;
return;
}
})
})
As you can see, each time a socket with same id connects, it will refer to the latest one.
Example If you did not understand:
Client connect to server with ID: 1337
search[1337] defined as --> websocket 1
A new connection with same ID: 1337
search[1337] becomes instead a variable refering to websocket 2 instead
Websockets provide a means to create a low-latency network "socket" between a browser and a server.
Note that the client here is the browser, not a tab on a browser.
If you need to manage multiple user sessions between the browser and server, you'll need to write code to do it yourself.
I'm using mrniko/netty-socketio (Java) to start a websocket server like this:
config = new Configuration();
config.setHostname("localhost");
config.setPort(8001);
server = new SocketIOServer(config);
server.addListeners(serviceClass);
server.start();
Then I'm using (the recommended) socketio/socket.io-client (JavaScript) to try to connect to the websocket server like this (all on the same server):
var socket = io("http://localhost:8001");
The connection is "blocked" at the server with the server printing:
8239 [nioEventLoopGroup-5-1] WARN com.corundumstudio.socketio.handler.AuthorizeHandler - Blocked wrong request! url: /socket.io/, ip: /127.0.0.1:48915
28889 [nioEventLoopGroup-5-2] WARN com.corundumstudio.socketio.handler.AuthorizeHandler - Blocked wrong request! url: /socket.io/, ip: /127.0.0.1:48916
Which occurs endlessly, as the client continues to retry the connection.
I can't seem to get the server to accept the connection. I've tried:
var socket = io("ws://localhost:8001");
But that gives the same outcome. I've also tried putting a trailing slash after the URL for both cases - makes no difference. I've also tried all combinations of using "localhost" or "127.0.0.1" at both the server and client, and so on.
The JavaScript page itself is being served up from a http server on localhost:8000. This does not appear to be a cross site issue as that gives an entirely different error at the browser.
Does anyone know what is going wrong and how to fix it?
In my case network monitoring accesses that port every 10 seconds. I had temporarily changed log4j.properties to ERROR level logging, but wanted to provide networking a path to use that would not cause excessive warn logging. Not sure if this was the best approach, but this is what I ended up doing.
config.setAllowCustomRequests(true);
By allowing custom requests the piece of code displaying the warning was bypassed in Authorizehandler.
I created a custom pipeline, that allowed me to switch out the wrongUrlHandler with a custom one to allow a safe path to use for monitoring.
public class CustomSocketIOChannelInitializer extends SocketIOChannelInitializer {
CustomWrongUrlHandler customWrongUrlHandler = null;
public CustomSocketIOChannelInitializer(Configuration configuration) {
customWrongUrlHandler = new CustomWrongUrlHandler(configuration);
}
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
addSslHandler(pipeline);
addSocketioHandlers(pipeline);
// Replace wrong url handler with our custom one to allow network monitoring without logging warnings.
pipeline.replace(SocketIOChannelInitializer.WRONG_URL_HANDLER, "CUSTOM_WRONG_URL_HANDLER", customWrongUrlHandler);
}
This is my custom handler:
#Sharable
public class CustomWrongUrlHandler extends ChannelInboundHandlerAdapter {
private final Logger log = LoggerFactory.getLogger(getClass());
Configuration configuration = null;
/**
* #param configuration
*/
public CustomWrongUrlHandler(Configuration configuration) {
this.configuration = configuration;
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
FullHttpRequest req = (FullHttpRequest) msg;
Channel channel = ctx.channel();
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri());
// Don't log when port is pinged for monitoring. Must use context that starts with /ping.
if (configuration.isAllowCustomRequests() && queryDecoder.path().startsWith("/ping")) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
channel.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE);
req.release();
//log.info("Blocked wrong request! url: {}, ip: {}", queryDecoder.path(), channel.remoteAddress());
return;
}
// This is the last channel handler in the pipe so if it is not ping then log warning.
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
ChannelFuture f = channel.writeAndFlush(res);
f.addListener(ChannelFutureListener.CLOSE);
req.release();
log.warn("Blocked wrong socket.io-context request! url: {}, params: {}, ip: {}", channel.remoteAddress() + " " + queryDecoder.path(), queryDecoder.parameters());
}
}
}
CustomSocketIOChannelInitializer customSocketIOChannelInitializer = new CustomSocketIOChannelInitializer(config);
server.setPipelineFactory(customSocketIOChannelInitializer);
I'm using the ws library for WebSockets in Node.js and
I'm trying this example from the library examples:
var sys = require("sys"),
ws = require("./ws");
ws.createServer(function (websocket) {
websocket.addListener("connect", function (resource) {
// emitted after handshake
sys.debug("connect: " + resource);
// server closes connection after 10s, will also get "close" event
setTimeout(websocket.end, 10 * 1000);
}).addListener("data", function (data) {
// handle incoming data
sys.debug(data);
// send data to client
websocket.write("Thanks!");
}).addListener("close", function () {
// emitted when server or client closes connection
sys.debug("close");
});
}).listen(8080);
All OK. It works, but running 3 clients, for instance, and sending "Hello!" from one will make the server only reply "Thanks!" to the client which sent the message, not to all.
How can I broadcast "Thanks!" to all connected clients when someone sends "Hello!"?
Thanks!
If you want to send out to all clients, you have to keep track of them. Here is a sample:
var sys = require("sys"),
ws = require("./ws");
// # Keep track of all our clients
var clients = [];
ws.createServer(function (websocket) {
websocket.addListener("connect", function (resource) {
// emitted after handshake
sys.debug("connect: " + resource);
// # Add to our list of clients
clients.push(websocket);
// server closes connection after 10s, will also get "close" event
// setTimeout(websocket.end, 10 * 1000);
}).addListener("data", function (data) {
// handle incoming data
sys.debug(data);
// send data to client
// # Write out to all our clients
for(var i = 0; i < clients.length; i++) {
clients[i].write("Thanks!");
}
}).addListener("close", function () {
// emitted when server or client closes connection
sys.debug("close");
for(var i = 0; i < clients.length; i++) {
// # Remove from our connections list so we don't send
// # to a dead socket
if(clients[i] == websocket) {
clients.splice(i);
break;
}
}
});
}).listen(8080);
I was able to get it to broadcast to all clients, but it's not heavily tested for all cases. The general concept should get you started though.
EDIT: By the way I'm not sure what the 10 second close is for so I've commented it out. It's rather useless if you're trying to broadcast to all clients since they'll just keep getting disconnected.
I would recommend you to use socket.io. It has example web-chat functionality out of the box and also provides abstraction layer from the socket technology on client (WebSockets are supported by Safari, Chrome, Opera and Firefox, but disabled in Firefox and Opera now due to security vulnerabilities in ws-protocol).