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)
Related
I am new to the MQTT world and I am trying to create a .Net 5.0 application that connects to a HiveMQ Cloud Broker.
I have created a free broker and I am able to connect to it with HiveMQ Websocket Client.
Here is a screenshot of my host.
I have created MQTT credentials for the host and I am able to connect over the sample client. Here is a screenshot of that client.
This works, I can publish and subscribe to the message queue.
However, now I am trying to translate this to c# and I am not able to connect. I am starting with this example project: https://github.com/rafiulgits/mqtt-client-dotnet-core
Then plugged the values from my cluster instance but I am a getting connection timeout on startup.
Here is what my service configuration looks like:
public static IServiceCollection AddMqttClientHostedService(this IServiceCollection services)
{
services.AddMqttClientServiceWithConfig(aspOptionBuilder =>
{
//var clientSettinigs = AppSettingsProvider.ClientSettings;
//var brokerHostSettings = AppSettingsProvider.BrokerHostSettings;
aspOptionBuilder
.WithCredentials("Test1", "xxxxx") //clientSettinigs.UserName, clientSettinigs.Password)
.WithClientId("clientId-jqE8uIw6Pp") //clientSettinigs.Id)
.WithTcpServer("xxxxxxxxxxxxxx.s2.eu.hivemq.cloud", 8884); //brokerHostSettings.Host, brokerHostSettings.Port);
});
return services;
}
private static IServiceCollection AddMqttClientServiceWithConfig(this IServiceCollection services, Action<AspCoreMqttClientOptionBuilder> configure)
{
services.AddSingleton<IMqttClientOptions>(serviceProvider =>
{
var optionBuilder = new AspCoreMqttClientOptionBuilder(serviceProvider);
configure(optionBuilder);
return optionBuilder.Build();
});
services.AddSingleton<MqttClientService>();
services.AddSingleton<IHostedService>(serviceProvider =>
{
return serviceProvider.GetService<MqttClientService>();
});
services.AddSingleton<MqttClientServiceProvider>(serviceProvider =>
{
var mqttClientService = serviceProvider.GetService<MqttClientService>();
var mqttClientServiceProvider = new MqttClientServiceProvider(mqttClientService);
return mqttClientServiceProvider;
});
return services;
}
I am not sure where I am going wrong, any help would be greatly appreciated.
You appear to be trying to connect to the WebSocket endpoint (port 8884) in your code, when I suspect you really should be using the normal TLS endpoint (port 8883)
Also you will need to use different clientid values if you want to have both clients connected at the same time as having matching will mean the clients will continuously kick each other off the broker.
(edit: on looking closer the client ids are actually different, but only in the last char)
I had this issue in two days ago and it seems coming form TLS confgurations/settings. By the way, my Startup.cs service injections and some configurations were same with yours. I have .NetCore app and I am trying to connect my own hivemq broker (cloud side).
In this case we need to add additional option to our mqtt client option build phase.
When I add this code, Auth problems gone.
.WithTls();
Here is part of the client option codes should like that
AddMqttClientServiceWithConfig(services,optionBuilder =>
{
var clientSettings = BrokerAppSettingsProvider.BrokerClientSettings;
var brokerHostSettings = BrokerAppSettingsProvider.BrokerHostSettings;
optionBuilder
.WithCredentials(clientSettings.UserName, clientSettings.Password)
.WithTls()
.WithTcpServer(brokerHostSettings.Host, brokerHostSettings.Port);
});
return services;
We can consider this as a different solution.
org.apache.ignite.internal.util.nio.GridNioServer#createSelector
// Create a new selector
selector = SelectorProvider.provider().openSelector();
if (addr != null) {
// Create a new non-blocking server socket channel
srvrCh = ServerSocketChannel.open();
srvrCh.configureBlocking(false);
if (sockRcvBuf > 0)
srvrCh.socket().setReceiveBufferSize(sockRcvBuf);
// Bind the server socket to the specified address and port
srvrCh.socket().bind(addr);
// Register the server socket channel, indicating an interest in
// accepting new connections
srvrCh.register(selector, SelectionKey.OP_ACCEPT);
}
return selector;
Why is the Ignite port listening not authenticated?
How can I set authentication?
Two parts:
It has to open the connection so that it can be told what the credentials are. If they're not valid, Ignite will disconnect
Ignite can only authenticate thin-clients out-of-the-box. I have not checked the code, but this could be a server or thick-client code path
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.
I am using a websocket to push data from a process (running in the background) to my electron application (renderer, it's a electron-vue app). Mostly this works great, the data is received and displayed instantly.
In some cases, however, I noticed that the websocket client seemed to buffer incoming messages and only trigger the receive-event after some delay, leading to messages received as a batch.
To verify that the server isn't buffering anything I ran a second connection and simply logged the data (chrome-addon), there all the data is received and processed instantly while my electron application delays the messages.
I am using ReconnectingWebsocket but also tried a plain websocket application:
let webSocket = new WebSocket('ws://0.0.0.0:7700')
webSocket.onopen = function(openEvent) {
console.log('WebSocket OPEN: ' + JSON.stringify(openEvent, null, 4))
}
webSocket.onclose = function(closeEvent) {
console.log('WebSocket CLOSE: ' + JSON.stringify(closeEvent, null, 4))
}
webSocket.onerror = function(errorEvent) {
console.log('WebSocket ERROR: ' + JSON.stringify(errorEvent, null, 4))
}
webSocket.onmessage = function(messageEvent) {
var wsMsg = messageEvent.data
console.log('WebSocket MESSAGE: ' + wsMsg)
}
The WebSocket MESSAGE: is only displayed with some delay. Is there any configuration option, like buffering on the client side or must the render process be called more often..?
Not sure of the solution but we have a demo app using Vue + Electron at https://github.com/firesharkstudios/butterfly-server-dotnet/tree/master/Butterfly.Example.Todo that also uses WebSockets. I've never seen a delay or buffering like you are seeing. Maybe you can compare the implementations to find a cause.
It turns out that it wasn't the websocket implementation but electron blocking the renderer process completely while scrolling, thus the delayed reception. I had to move the websocket connection out of the renderer and tunnel all messages using the IPC system.
How can I know on the server side when a client connected or disconnected from server?
Does ZeroC Ice provides some callback functions for those events?
Minimal demo:
Server side
try(com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(args))
{
com.zeroc.Ice.ObjectAdapter adapter =
communicator.createObjectAdapterWithEndpoints("Hello", "default -h localhost -p 10000");
adapter.add(new HelloI(), com.zeroc.Ice.Util.stringToIdentity("hello"));
adapter.activate();
communicator.waitForShutdown();
}
Client side
try(com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(args))
{
HelloPrx hello = HelloPrx.checkedCast(communicator.stringToProxy("hello:default -h localhost -p 10000"));
hello.sayHello();
}
From the Server side you can check current.con member and register a close callback if it's a connection that hasn't been seen before see setCloseCallback
current is com.zeroc.Ice.Current parameter passed to all servant methods, for example in sayHello implementation you can do
#Override
public void sayHello(int delay, com.zeroc.Ice.Current current)
{
// Check if current.con is a new connection, you will
// need to keep track of that in your code.
// Install a close callback for the connection.
current.con.setCloseCallback(con ->
{
// Close callback
});
}