I have two file in a nodejs- express application
first.pug
var socket = io.connect('//'+document.location.hostname+':'+document.location.port, {
query: {
token: "XXXXXX"
}
});
socket.on('connect', (s) => {
console.log('connected!');
socket.emit('join123', 'room1');
});
second.pug
var socket = io.connect('//'+document.location.hostname+':'+document.location.port, {
query: {
token: "XXXXXX"
}
});
socket.on('join123', function (data) {
console.log("join.group========================"+data);
});
Nodejs Server side
io.on('connection', (socket) => {
console.log('a user connected');
socket.join('join123');
});
I dont see any message in second.pug when a message is pulished from first.pug
The socket.io connection made by second.pug never receives a message because your server never sends it a message.
Here's what first.pug does:
It creates a socket.io connection to your server.
When that connection succeeds, it sends a join123 message to that server.
Here's what your socket.io server does:
It listens for connecting clients.
When a client connects, it puts that client into the join123 room.
No messages are sent out to any of the connected clients.
Note: there is no listener on the server for the join123 message that the client sent so likely something is wrong there.
Here's what second.pug does:
It create a socket.io connection to your server.
It listens for a join123 message to be sent to it.
But, nothing ever sends a join123 message to second.pug, so second.pug never receives that message. first.pug sends a join123 message to your server, but the server never sends that to anyone else. The act of doing socket.join('join123') does not cause any messages to be sent. It just adds the socket to a room by that name. If you want the second.pug to get a join123 message, you would have to write code on your server that actually sends that message either to all connections or somehow just to the second.pug connection.
Related
I have a ratchet server, that I try to access via Websocket. It is similar to the tutorial: logging when there is a new client or when it receives a message. The Ratchet server reports having successfully established a connection while the Kotlin client does not (the connection event in Kotlin is never fired). I am using the socket-io-java module v.2.0.1. The client shows a timeout after the specified timeout time, gets detached at the server and attaches again after a short while, just as it seems to think, the connection did not properly connect (because of a missing connection response?).
The successful connection confirmation gets reported to the client, if the client is a Websocket-Client in the JS-console of Chrome, but not to my Kotlin app. Even an Android emulator running on the same computer doesn´t get a response (So I think the problem is not wi-fi related).
The connection works fine with JS, completing the full handshake, but with an Android app it only reaches the server, but never the client again.
That´s my server code:
<?php
namespace agroSMS\Websockets;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
class SocketConnection implements MessageComponentInterface
{
protected \SplObjectStorage $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
error_log("New client attached");
}
function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
error_log("Client detached");
}
function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
function onMessage(ConnectionInterface $from, $msg)
{
error_log("Received message: $msg");
// TODO: Implement onMessage() method.
}
}
And the script that I run in the terminal:
<?php
use Ratchet\Server\IoServer;
use agroSMS\Websockets\SocketConnection;
use Ratchet\WebSocket\WsServer;
use Ratchet\Http\HttpServer;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new SocketConnection()
)
)
);
$server->run();
What I run in the browser for tests (returns "Connection established" in Chrome, but for some reason not in the Browser "Brave"):
var conn = new WebSocket('ws://<my-ip>:80');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
};
What my Kotlin-code looks like:
try {
val uri = URI.create("ws://<my-ip>:80")
val options = IO.Options.builder()
.setTimeout(60000)
.setTransports(arrayOf(WebSocket.NAME))
.build()
socket = IO.socket(uri, options)
socket.connect()
.on(Socket.EVENT_CONNECT) {
Log.d(TAG, "[INFO] Connection established")
socket.send(jsonObject)
}
.once(Socket.EVENT_CONNECT_ERROR) {
val itString = gson.toJson(it)
Log.d(TAG, itString)
}
}catch(e : Exception) {
Log.e(TAG, e.toString())
}
After a minute the Kotlin code logs a "timeout"-error, detaches from the server, and attaches again.
When I stop the script on the server, it then gives an error: "connection reset, websocket error" (which makes sense, but why doesn´t he get the connection in the first time?)
I also tried to "just" change the protocol to "wss" in the url, in case it might be the problem, even though my server doesn´t even work with SSL, but this just gave me another error:
[{"cause":{"bytesTransferred":0,"detailMessage":"Read timed out","stackTrace":[],"suppressedExceptions":[]},"detailMessage":"websocket error","stackTrace":[],"suppressedExceptions":[]}]
And the connection isn´t even established at the server. So this try has been more like a down-grade.
I went to the github page of socket.io-java-client to find a solution to my problem there and it turned out, the whole problem was, that I misunderstood a very important concept:
That socket.io uses Websockets doesn´t mean it is compatible with Websockets.
So speaking in clear words:
If you use socket.io at client side, you also need to use it at the server side and vice versa. Since socket.io sends a lot of meta data with its packets, a pure Websocket-server will accept their connection establishment, but his acknowledgement coming back will not be accepted by the socket.io client.
You have to go for either full socket.io or full pure Websockets.
Here is my paho client code
// Create a client instance
client = new Paho.MQTT.Client('127.0.0.1', 1883, "clientId");
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
// connect the client
client.connect({onSuccess:onConnect});
// called when the client connects
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
client.subscribe("/World");
message = new Paho.MQTT.Message("Hello");
message.destinationName = "/World";
client.send(message);
}
// called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
}
}
// called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:"+message.payloadString);
}
On Rabbitmq server everything is default seetings. When i run this code i get WebSocket connection to 'ws://127.0.0.1:1883/mqtt' failed: Connection closed before receiving a handshake response
What i am missing ?
From my personal experience with Paho MQTT JavaScript library and RabbitMQ broker on windows, here is a list of things that you need to do to be able to use MQTT from JS from within a browser:
Install rabbitmq_web_mqtt plugin (you may find latest binary here, copy it to "c:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.2\plugins\", and enable from command line using "rabbitmq-plugins enable rabbitmq_web_mqtt".
Of course, MQTT plugin also needs to be enabled on broker
For me, client was not working with version 3.6.1 of RabbitMQ, while it works fine with version 3.6.2 (Windows)
Port to be used for connections is 15675, NOT 1883!
Make sure to specify all 4 parameters when making instance of Paho.MQTT.Client. In case when you omit one, you get websocket connection error which may be quite misleading.
Finally, here is a code snippet which I tested and works perfectly (just makes connection):
client = new Paho.MQTT.Client("localhost", 15675, "/ws", "client-1");
//set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
//connect the client
client.connect({
onSuccess : onConnect
});
//called when the client connects
function onConnect() {
console.log("Connected");
}
//called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:" + responseObject.errorMessage);
}
}
//called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:" + message.payloadString);
}
It's not clear in the question but I assume you are running the code above in a web browser.
This will be making a MQTT connection over Websockets (as shown in the error). This is different from a native MQTT over TCP connection.
The default pure MQTT port if 1883, Websocket support is likely to be on a different port.
You will need to configure RabbitMQ to accept MQTT over Websockets as well as pure MQTT, this pull request for RabbitMQ seams to talk about adding this capability. It mentions that this capability was only added in version 3.6.x and that the documentaion is still outstanding (as of 9th Feb 2016)
guys
I'm trying to send message to server and get response on client side, also I'm trying to publish another message on server using the same endpoint.
I don't get response on client side, but subscribers get published messages with success
Server side code:
if (!someCondition)
{
_bus.Reply(new BookingStatus(message, Status.Occupied));
}
else
{
_bus.Reply(new BookingStatus(message, Status.Ok));
_bus.Publish(new RoomBooked(message, Guid.NewGuid()));
//some logic
}
Code for config bus:
BusConfiguration busConfiguration = new BusConfiguration();
busConfiguration.EndpointName("NServiceBusDemo");
busConfiguration.UseTransport<MsmqTransport>();
busConfiguration.UseSerialization<JsonSerializer>();
busConfiguration.EnableInstallers();
busConfiguration.UsePersistence<InMemoryPersistence>();
busConfiguration.AutoSubscribe();
DefaultFactory defaultFactory = LogManager.Use<DefaultFactory>();
defaultFactory.Directory(#"..\..\..\logs");
defaultFactory.Level(LogLevel.Warn);
var bus = Bus.Create(busConfiguration);
return bus;
I'm doing a system using expressjs + socket.io(with SessionSocket plugin) + mongoosejs.
The server was build like this:
var mongoose = require('mongoose'),
connect = require('connect'),
express = require('express'),
http = require('http'),
io = require('socket.io');
// hold cookieParser and sessionStore for SessionSocket
var cookieParser = express.cookieParser('your secret sauce'),
sessionStore = new connect.middleware.session.MemoryStore();
// create express server
var app = express();
// config express server
require('./config/express')(app, config, cookieParser, sessionStore);
// Express3 requires a http.Server to attach socke.io
var server = http.createServer(app);
// attach socket.io
var sio = io.listen(server);
sio.set('log level', 2);
// create SessionSocket
var SessionSockets = require('session.socket.io'),
sessionSockets = new SessionSockets(sio, sessionStore, cookieParser);
// setup SessionSocket
sessionSockets.on('connection', function(err, socket, session) {
socket.join(session.user._id);
socket.emit('message', {
title: "welcome",
msg: "welcome to selink"
});
});
// config express server route
app.get('/some-action', **SomeMongooseFunction**);
// start server
server.listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
In the express route handler("SomeMongooseFunction", defined in other file), after processed user action(query, modify DB etc.), I want sent a real-time notification to the user or other online user. so I thing I must pass "sio" object into the "SomeMongooseFunction", the example above has only one route, but actually I have dozens of routes, It gonna looks ugly if I do so.
or in the setup SessionSocket part, I think could paste the sio into the user's session. but, I'm not sure this way is right or not.
so, is there any other way to get sio reference in the express handler? (it will be nice if I can refer sio like a global variable, but global is evil...)
thanks for any ideas.
You're storing user ID from session into Socket.IO rooms manager. Now you have somehow get the target's user ID
and send the event message for this user.
For your case, you are using notification entity so lets do it:
//client side - send a notification for a specific user.
var note = {
from: userID, //sender
target: id, //receiver
type: type //type of notification
}
socket.emit('notification', note);
target field is the target user ID, this user will receive the notification status.
type here is just for illustrate if you wanna to handle more than one type of notifications.
socket.emit('notification', note); this part is the most important one. It will send the note JSON object
to notification event. This event must be registered on you server side Socket.IO page;
//server side - receive JSON data on notification event
socket.on('notification', function(data) {
io.sockets.in(data.target).emit('notification', data);
});
NOTE: I use 'io' instead of 'sio'.
notification event is registered and will catch all client messages directed to it. data is the
JSON object we sent before, so io.sockets.in().emit()
Once again on client. We must catch all notification event.
//client side - the final destination
socket.on('notification', function(data) {
//DO SOME JQUERY STUFF TO ALERT THIS TARGET USER FROM THE MESSAGE RECEIVED.
console.log("User: " + data.from + " sent you this notification");
});
The steps we can conclude are:
Sender user sends a message for notification event on server-side that contains target user
Server gets the message and now knows which event and target must be receive the message.
Server sends the message to the correct target on specified socket.io event.
You can use this analogy for any case you have to send Socket.IO messages for a specific user.
The goal of my simple try is to display online user list. I mean display not socket.io ID but display user profile. When authorized user connects to my server, open socket.io channel, it is required to get his profile and send message to other connected user that new user (Name, email, etc) has being connected. I saw many examples how to do it within authorization, but it doesn't handle a disconnect. What i want to do and what i can't do in pseudocode:
var io = require("socket.io").listen(server);
io.set("authorization", function(data, callback){
// ... some code...
callback(null, true);
});
io.sockets.on('connection', function (socket) {
var UserProfile = passport.getUserProfile(socket.id)
io.sockets.emit('user_connected', {UserProfile: UserProfile, socketID: socket.id});
io.sockets.on('disconnect', function (socket) {
io.sockets.emit('user_disconnected', {socketID: socket.id});
});
});
This is a pseudocode!
My stack is overflowed. I just want to link socket.io ID and passport account together within connection. How can i do it?
I got the same problem, and my solution is the following (hopefully someone gets a better idea):
i add the username to the render call (using jade):
res.render('chatroom', {username: req.user.username});
right after connecting to socket on the client (io.connect), i emit a
message to the server, with the username as parameter, using the connect event on the client (socket.on('connect', function (data) { ... });
on the server, i store the username in an object (clients[socket.id]
= username)
after that, i get the username in every socket message by accessing
the clients object