I am working on an MQTT application in eclipse. I was earlier using mqtt-dashboard as the public broker and was able to see the messages that I was publishing on the dashboard. For some reason, this site is down so I switched to mosquitto. My code is same but still I am not able to publish messages to this broker. My code is as follows:
public static void main(String[] args) {
String topic = "home automation systems";
String content = "I am a test message";
int qos = 2;
String broker = "tcp://test.mosquitto.org:1883";
String clientId = "home automation";
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
System.out.println("Connecting to broker: "+broker);
sampleClient.connect(connOpts);
System.out.println("Connected");
System.out.println("Publishing message: "+content);
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
System.out.println("Message published");
sampleClient.disconnect();
System.out.println("Disconnected");
System.exit(0);
}
catch(MqttException me) {
System.out.println("reason "+me.getReasonCode());
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
me.printStackTrace();
}
}
}
I am trying to see the published message on this dashboard: http://test-mosquitto.herokuapp.com/
but cannot see my message. Please correct me if I am missing something. I am new to it. Thanks.
If you expect a message to show up on that "dashboard", it would need to be published with the retained flag set - that web app can only show retained messages, not regular ephemeral ones.
Related
I'm trying to send push message using the emulator of pubsub, I'm using spring boot too, this is my configuration:
Dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
</dependency>
My bean:
#Configuration
#AutoConfigureBefore(value= GcpPubSubAutoConfiguration.class)
#EnableConfigurationProperties(value= GcpPubSubProperties.class)
public class EmulatorPubSubConfiguration {
#Value("${spring.gcp.pubsub.projectid}")
private String projectId;
#Value("${spring.gcp.pubsub.subscriptorid}")
private String subscriptorId;
#Value("${spring.gcp.pubsub.topicid}")
private String topicId;
#Bean
public Publisher pubsubEmulator() throws IOException {
String hostport = System.getenv("PUBSUB_EMULATOR_HOST");
ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build();
try {
TransportChannelProvider channelProvider =
FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel));
CredentialsProvider credentialsProvider = NoCredentialsProvider.create();
// Set the channel and credentials provider when creating a `TopicAdminClient`.
// Similarly for SubscriptionAdminClient
TopicAdminClient topicClient =
TopicAdminClient.create(
TopicAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build());
ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
// Set the channel and credentials provider when creating a `Publisher`.
// Similarly for Subscriber
return Publisher.newBuilder(topicName)
.setChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build();
} finally {
channel.shutdown();
}
}
}
Of course, I have set PUBSUB_EMULATOR_HOST system variable to localhost:8085, where is the emulator running
I created a rest controller for testing:
for send push message
#Autowired
private Publisher pubsubPublisher;
#PostMapping("/send1")
public String publishMessage(#RequestParam("message") String message) throws InterruptedException, IOException {
Publisher pubsubPublisher = this.getPublisher();
ByteString data = ByteString.copyFromUtf8(message);
PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).build();
ApiFuture<String> future = pubsubPublisher.publish(pubsubMessage);
//pubsubPublisher.publishAllOutstanding();
try {
// Add an asynchronous callback to handle success / failure
ApiFutures.addCallback(future,
new ApiFutureCallback<String>() {
#Override
public void onFailure(Throwable throwable) {
if (throwable instanceof ApiException) {
ApiException apiException = ((ApiException) throwable);
// details on the API exception
System.out.println(apiException.getStatusCode().getCode());
System.out.println(apiException.isRetryable());
}
System.out.println("Error publishing message : " + message);
System.out.println("Error publishing error : " + throwable.getMessage());
System.out.println("Error publishing cause : " + throwable.getCause());
}
#Override
public void onSuccess(String messageId) {
// Once published, returns server-assigned message ids (unique within the topic)
System.out.println(messageId);
}
},
MoreExecutors.directExecutor());
}
finally {
if (pubsubPublisher != null) {
// When finished with the publisher, shutdown to free up resources.
pubsubPublisher.shutdown();
pubsubPublisher.awaitTermination(1, TimeUnit.MINUTES);
}
}
return "ok";
for get message:
#PostMapping("/pushtest")
public String pushTest(#RequestBody CloudPubSubPushMessage request) {
System.out.println( "------> message received: " + decode(request.getMessage().getData()) );
return request.toString();
}
I have created my topic and subscription in the emulator, I followed this tutorial:
https://cloud.google.com/pubsub/docs/emulator
I'm set the endpoint "pushtest" for get push message in the emulator, with this command:
python subscriber.py PUBSUB_PROJECT_ID create-push TOPIC_ID SUBSCRIPTION_ID PUSH_ENDPOINT
But when I run the test, doesn't reach "/pushtest" endpoint and I'm getting this error:
Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask#265d5d05
[Not completed, task = java.util.concurrent.Executors$RunnableAdapter#a8c8be3
[Wrapped task = com.google.common.util.concurrent.TrustedListenableFutureTask#1a53c57c
[status=PENDING, info=[task=[running=[NOT STARTED YET], com.google.api.gax.rpc.AttemptCallable#3866e1d0]]]]]
rejected from java.util.concurrent.ScheduledThreadPoolExecutor#3f34809a
[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]
for assurance that the emulator is running ok, I'm run the test in python with the following command:
python publisher.py PUBSUB_PROJECT_ID publish TOPIC_ID
And I'm getting messages correctly in "pushtest" endpoint.
I don't know why sorry for my hazing.
Thanks for your help.
I found the problem.
Only comment this line in the bean
channel.shutdown();
HAHA very simple.
I recently work with Topic in jms and I have a problem. My TopicSubscriber didn't receive message from publisher and I don't understand why.
Here is my TopicPublisher:
public class Publisher
{
private static final String CONNECTION_URL = "tcp://localhost:61616";
public static void main(String[] args) throws Exception
{
BrokerService service = BrokerFactory.createBroker(new URI("broker:(" + CONNECTION_URL + ")"));
service.start();
TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(CONNECTION_URL);
// create a topic connection
TopicConnection topicConn = connectionFactory.createTopicConnection();
// create a topic session
TopicSession topicSession = topicConn.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
// lookup the topic object
Topic topic = topicSession.createTopic("test");
// create a topic publisher
TopicPublisher topicPublisher = topicSession.createPublisher(topic);
topicPublisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// create the "Hello World" message
TextMessage message = topicSession.createTextMessage();
message.setText("Hello World");
// publish the messages
topicPublisher.publish(message);
// print what we did
System.out.println("Message published: " + message.getText());
// close the topic connection
topicConn.close();
}
}
My TopicSubscriber:
public class Subscriber
{
private static final String CONNECTION_URL = "tcp://localhost:61616";
public static void main(String[] args) throws Exception
{
TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(CONNECTION_URL);
// create a topic connection
TopicConnection topicConn = connectionFactory.createTopicConnection();
// create a topic session
TopicSession topicSession = topicConn.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
Topic topic = topicSession.createTopic("test");
// create a topic subscriber
TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
// start the connection
topicConn.start();
// receive the message
TextMessage message = (TextMessage) topicSubscriber.receiveNoWait();
// print the message
System.out.println("Message received: " + message.getText());
// close the topic connection
topicConn.close();
}
}
In my subscriber I've got a NullPointer on message.getText()
What is that problem? What am I doing wrong and how it can be fixed?
It appears that you're sending the message before you create the subscription. JMS topics use publish-subscribe semantics where any message published goes to all subscriptions. If there are no subscriptions then the message is discarded.
Also, since you're using receiveNoWait() you're severely reducing the chance that your client will ever get a message. In order for your client to actually receive a message the message would have to be sent in between the time you call createSubscriber(topic) and the time you call receiveNoWait(). Since those 2 calls happen very close together the window of time is very small.
If you really want your subscriber to get a message then run Subscriber first and use receive() rather than receiveNoWait() and then run Publisher. This will ensure the subscription exists when the message is sent and that the client waits to receive the message before exiting.
I'm newbie in MQTT.
I am implementing MQTT in java and I am using below code for publisher to publish to a particualr topic,
public void publish()
{
MqttClient myClient = null;
MqttConnectOptions connOpt;
try {
// Subscription with Brokers
connOpt = new MqttConnectOptions();
connOpt.setAutomaticReconnect(true);
connOpt.setCleanSession(true);//if your not setting cleanSession to false then subscriptions shouldn't be persisted.
String clientID = UUID.randomUUID().toString().replace("-", "");
System.out.println("clientID " + clientID);
myClient = new MqttClient("tcp://192.168.10.500:1883", clientID);
myClient.connect(connOpt);
String myTopic = "Device1";
MqttTopic topic = myClient.getTopic(myTopic);
int pubQoS = 0;
MqttMessage message = new MqttMessage("mqttMessage".getBytes());
message.setQos(pubQoS);
message.setRetained(false);
MqttDeliveryToken token = null;
token = topic.publish(message);
System.out.println("publish successful with the message :: " + message);
// Wait until the message has been delivered to the broker
token.waitForCompletion();
} catch (MqttException me) {
} catch (Exception e) {
}
}
And then I am using below code to read the published message for a particular topic as a subscriber,
public void subscribe()
{
try {
MqttConnectOptions connOpt;
// Subscription with mqttBrokerEndPoint
connOpt = new MqttConnectOptions();
connOpt.setAutomaticReconnect(true);
connOpt.setCleanSession(true);//if your not setting cleanSession to false then subscriptions shouldn't be persisted.
String clientID = UUID.randomUUID().toString().replace("-", "");
System.out.println("clientID " + clientID);
MqttSubscriber mqttConnection = new MqttSubscriber();
myClient = new MqttClient("tcp://192.168.10.500:1883" clientID);
myClient.setCallback(mqttConnection);
myClient.connect(connOpt);
myClient.subscribe("Device1");
} catch (MqttException e) {
}
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
try {
System.out.println(message);
boolean isValidClient = true;// Here i need to check if this is the valid subscriber for the message publised on topic "Device1"
//if(isValidClient) {
if(message != null) {
System.out.println("message" + message.toString());
}
myClient.unsubscribe("Device1");
myClient.disconnect();
//}
}
catch(Exception e){}
}
The above implementation is working fine as it is.
Since I am very new to mqtt I have some doubts with the above implementation.
1) Is Client id in both publisher and subscriber should be SAME for one particular flow ?
or should different in both publisher and subscriber as above : which can be randomly generated?
String clientID = UUID.randomUUID().toString().replace("-", "");
This randomly generated clientID is working fine with both subscribing and publishing.
But, If I use same client for both publisher and subscriber and validate subscriber?
I mean use "clientID" myClient = new MqttClient(mqttBrokerEndPoint, "clientID"); in subsriber and then same "clientID" myClient = new MqttClient(mqttBrokerEndPoint, "clientID"); in publisher
I am getting the below socket error in mqtt broker console(used windows version) ,
1549414715: Socket error on client 82, disconnecting.
1549414715: New client connected from 192.168.10.500 as clientID (c1, k60).
1549414715: No will message specified.
1549414715: Sending CONNACK to 82 (0, 0)
1549414716: New connection from 192.168.10.500 on port 1883.
1549414716: Client 82 already connected, closing old connection.
1549414716: Socket error on client 82, disconnecting.
1549414716: New client connected from 192.168.10.500 as clientID (c1, k60).
1549414716: No will message specified.
1549414716: Sending CONNACK to 82 (0, 0)
1549414716: New connection from 192.168.10.500 on port 1883.
1549414716: Client 82 already connected, closing old connection.
1549414716: Socket error on client 82, disconnecting.
1549414716: New client connected from 192.168.10.500 as clientID (c1, k60).
1549414716: No will message specified.
1549414716: Sending CONNACK to 82 (0, 0)
and the above program is not working.
Can't we use same clientID for for both subscriber and publisher? Why is it resulting in socket error and programs not working?
2) Is username and password mandatory while implementation? Or can we establish a connection without those 2 below properties?
connOpt.setUserName(USERNAME);
connOpt.setPassword(PASSWORD.toCharArray());
3) Is pubQoS is mandatory to be used for publisher? I am currently using it as zero '0' ?
MqttMessage message = new MqttMessage(mqttMessage.getBytes());
message.setQos(0);
message.setRetained(false);
Also is retained attribute is mandatory for publisher?
4) Is these 2 below attributes mandatory while subscribing? I am using as below in code.
connOpt.setAutomaticReconnect(true);
connOpt.setCleanSession(true);//if your not setting cleanSession to
false then subscriptions shouldn't be persisted.
5) Also, Once Message is received from MQTT publisher in to MessageArrived callback as below, how to validate if this is valid subscriber and proceed with further logic?
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
try {
System.out.println(message);
boolean isValidClient = true;// Here i need to check if this is the valid subscriber for the message publised on topic "Device1"
//if valid subscriber only i need to read message publised on the topic "Device1"
**//if(isValidClient) {**
if(message != null) {
System.out.println("message" + message.toString());
}
myClient.unsubscribe("Device1");
myClient.disconnect();
//}
}
catch(Exception e){}
I mean which attribute MQTT API to check that this message is only sent for this subscriber and he can proceed further to use the message received in message arrived callback?
I.e, which attribute of MQTT api can be used to check if the received message is related to current PROCESS/STEP.(In SUbscriber Program as below)
IS the topic is the only common attributes between subscriber and publisher to validate subscriber in messageArrived callback ? or do we have any other common attribute to check a valid contract between subscriber and publisher?
Or should we used clientID to validate subscriber? But if i use the same clientID for subscriber and publisher I am getting the socket error which i have mentioned in point number 1.
How to proceed further on this?
1) You cannot use same client id for two mqtt client. Client ids for mqtt must be unique. You can create different topic for handling different operations. You can refer to the below answer
Two paho.mqtt clients subscribing to the same client localy
2) Username and password is optional. If your mqtt server is configured to use username and password then your client also need to pass username and password to mqtt server. Refer to the below link for understanding the code usage
How can i connect a Java mqtt client with username and password to an emqttd(EMQ) broker?
If you want advanced level go for tls/ssl security
https://dzone.com/articles/secure-communication-with-tls-and-the-mosquitto-broker
3) QOS - The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message that defines the guarantee of delivery for a specific message. Refer to the below link for more information on qos
https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/
4) Auto Reconnect (True) - If mqtt server is disconnected during run time then client tries to reconnect to the server.
Clean Session (True) - On reconnecting to the mqtt server all older sessions associated with same client id will be deleted.
Clean Session (False) - On reconnecting to the mqtt server all older sessions associated with same client id will be retained. Mqtt server in some cases retains messages based on QOS level.
5) Try to create multiple topics for multiple operations. In message arrived method you can check on which topic message has arrived. Then you can call different methods based on that. Below codes are one of the way. You can find out best way that suits your needs. Cheers !!!!!
#Override
public void deliveryComplete(IMqttDeliveryToken token)
{
try
{
if(token.getTopics()[0].equals("TOPIC_A"))
{
//Do something
}
else if(token.getTopics()[0].equals("TOPIC_B"))
{
//Do something
}
}
catch (Exception e)
{
MQTTLogger.logSevere(e);
}
}
Json Format for data
First message
{
"client-name":"client1"
"data":""
}
Second message
{
"client-name":"client2"
"data":""
}
I am using Paho java client library for my on android App. Code provided below.
MqttAndroidClient client_Panic = new MqttAndroidClient(this.getApplicationContext(), serverURL, CLIENT_ID);
try {
MqttConnectOptions options = new MqttConnectOptions();
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
options.setCleanSession(false);
options.setKeepAliveInterval(90);
options.setConnectionTimeout(100);
IMqttToken token = client_Panic.connect(options);
//Few callbacks
} catch (MqttException e) {
e.printStackTrace();
}
And publishing messages, when required
String msg = "messages";
MqttMessage message = new MqttMessage();
message.setPayload(msg.getBytes());
try {
client_Panic.publish(topic, message);
} catch (MqttException e) {
e.printStackTrace();
}
It is working fine, but somehow incomplete. What I need is, whenever other client subscribed to same topic, should get the last retained message, which publisher might had published earlier.
For that I searched on their documentation, I got
protected void setWill(String topic,
MqttMessage msg,
int qos,
boolean retained)
So setWill as per documentation have the option to enable the retained option. So I tried with
options.setConnectionTimeout(100);
options.setWill(topic,null,2,true); // This place I added
IMqttToken token = client_Panic.connect(options);
But got error java.lang.IllegalArgumentException at org.eclipse.paho.client.mqttv3.MqttConnectOptions.validateWill on the line containing options.setWill.
Is setWill is the correct method for enabling retained true on android, if yes then what parameters need to be provided or else their is any other method for enabling it on android? TIA.
The Will is a very specific message that is only published if the client disconnects uncleanly from the broker (e.g. network drops).
You can not set a null message as the Will message which is what the error is about.
The retained state is specific to a given message so you do not set it globally, it is set on each message. To mark a message as retained when you just call the setRetained(boolean) e.g.
String msg = "messages";
MqttMessage message = new MqttMessage();
message.setRetained(true);
message.setPayload(msg.getBytes());
try {
client_Panic.publish(topic, message);
} catch (MqttException e) {
e.printStackTrace();
}
I have downloaded the source from github from this link: https://github.com/twitter/cloudhopper-smpp
Assuming I want to test receiving message between clients so I create a server and 2 clients. To run server, I used the command "make server". Then in other machine, a client connected to my server and send 1 message to other client which has phone number "123456" using following code
submit0.setSourceAddress(new Address((byte)0x03, (byte)0x00, "654321"));
submit0.setDestAddress(new Address((byte)0x01, (byte)0x01, "123456"));
submit0.setShortMessage(textBytes);
SubmitSmResp submitResp = session0.submit(submit0, 10000);
How can the client which has phone number "123456" get message content from phone number "654321"?
Thanks!
When you are creating sessionHandler like this,
DefaultSmppSessionHandler sessionHandler = new ClientSmppSessionHandler();
This ClientSmppSessionHandler should be extended to DefaultSmppSessionHandler.
There are 2 listeners.
Please see below example.
public class ClientSmppSessionHandler extends DefaultSmppSessionHandler {
private static final Logger logger = LoggerFactory.getLogger(ClientSmppSessionHandler.class);
public ClientSmppSessionHandler() {
super(logger);
}
#Override
public void firePduRequestExpired(PduRequest pduRequest) {
logger.warn("PDU request expired: {}", pduRequest);
}
#Override
public PduResponse firePduRequestReceived(PduRequest pduRequest) {
PduResponse response = pduRequest.createResponse();
logger.info("SMS Received: {}", pduRequest);
if (pduRequest.getCommandId() == SmppConstants.CMD_ID_DELIVER_SM) {
DeliverSm mo = (DeliverSm) pduRequest;
int length = mo.getShortMessageLength();
Address source_address = mo.getSourceAddress();
Address dest_address = mo.getDestAddress();
byte[] shortMessage = mo.getShortMessage();
String SMS= new String(shortMessage);
logger.info(source_address + ", " + dest_address + ", " + SMS);
}
return response;
}
}