I am getting "java.io.eof" exception,when i am trying to subscribe mqtt client. I am using eclipse paho library and using mosquitto broker. I am not getting any answer of this,so please help me why this happens ?
Mqtt connection and subscribe
I am using this code for connecting and subscribing to mosquitto
private void buildClient(String clientId){
log.debug("Connecting... "+clientId);
try {
mqttClient = new MqttClient(envConfiguration.getBrokerUrl(), clientId,new MemoryPersistence());
System.out.println(mqttClient.isConnected());
} catch (MqttException e) {
log.debug("build client stopped due to "+e.getCause());
}
chatCallback = new ChatCallback(this.userService,this);
mqttClient.setCallback(chatCallback);
mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setCleanSession(true);
}
#Override
public void connect(String clientId,String topic) {
try{
if(mqttClient == null || !mqttClient.getClientId().equals(clientId)){
buildClient(clientId);
mqttClient.connect(mqttConnectOptions);
subscribe(clientId,topic);
}
}catch (Exception e) {
log.debug("connection attempt failed "+ e.getCause() + " trying...");
}
}
#Override
public void subscribe(String clientId,String topic) throws MqttException {
if(mqttClient != null && mqttClient.isConnected()){
mqttClient.subscribe(topic,0);
/*try {
log.debug("Subscribing... with client id :: " + clientId + "topic");
mqttClient.subscribe(topic,2);
} catch (MqttException e) {
log.debug("subscribing error.."+e.getLocalizedMessage());
}*/
}
}
}
And mqtt call back
#Override
public void connectionLost(Throwable arg0) {
log.debug("Connection lost... attampting retrying due to "
+ arg0);
arg0.printStackTrace();
// chatServiceimpl.connect();
}
#Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
log.debug("delivered message" + arg0);
// TODO Auto-generated method stub
}
#Override
public void messageArrived(String arg0, MqttMessage arg1) throws Exception {
log.debug("Message recived..." + arg1.toString());
userService.saveChat(arg1.toString());
}
I am facing this error when i am subscribing to mosquitto
Error logs
2015-11-30/18:19:00.877 [MQTT Call: 25287] DEBUG c.s.s.ChatCallback: Message recived...{ "id":"37153topic25287T1448886285.79573", "from":"37153", "to":"25287", "chatBody":[{"type": "text", "message":"The fact "}]}
2015-11-30/18:19:00.878 [MQTT Call: 25287] DEBUG c.s.s.u.UserService: Saving chat...
2015-11-30/18:19:00.883 [MQTT Call: 25287] DEBUG c.s.s.u.UserService: Get user by id::37153
2015-11-30/18:19:00.885 [MQTT Call: 25287] DEBUG c.s.s.u.UserService: Get user by id::25287
2015-11-30/18:19:00.886 [MQTT Rec: 25287] DEBUG c.s.s.ChatCallback: Connection lost... attampting retrying due to Connection lost (32109) - java.io.EOFException
Connection lost (32109) - java.io.EOFException
at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:138)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException
at java.io.DataInputStream.readByte(DataInputStream.java:267)
at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:56)
at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:100)
... 1 more
Mosquitto Logs
1448889230: Client 25287 disconnected.
1448889230: New client connected from 192.168.2.63 as 25287 (c0, k60).
1448889231: New connection from 192.168.2.242 on port 1883.
1448889231: Client 25287 already connected, closing old connection.
1448889231: Client 25287 disconnected.
1448889231: New client connected from 192.168.2.242 as 25287 (c1, k60).
1448889231: New connection from 192.168.2.63 on port 1883.
1448889231: Client 25287 already connected, closing old connection.
1448889231: Client 25287 disconnected.
1448889231: New client connected from 192.168.2.63 as 25287 (c0, k60).
1448889269: New connection from 192.168.2.242 on port 1883.
You have multiple clients connecting to the broker with the same clientid, this is not allowed and as one connects the broker will disconnect the currently connected client.
If both clients have automatic reconnection logic then they will just continue to kick each other off.
Change the client id on one of the clients.
As hardillb mentioned above, you have multiple clients connecting. Server (mosquitto) will disconnect the old connection when it receives a connect request from the same client again.
use the isConnected() method on MqttClient object to know if its connected. for eg.
if (! m_client.isConnected()) {
// reconnect
}
Related
I am using Spring Integration with Spring Boot. I have a TCP Client [TcpNetClientConnectionFactory] with TcpOutboundGateway setup. I can see the below warnings in Production[No publisher available to publish].
Log Snippet
Based on my checking this warning is shown when the org.springframework.context.ApplicationEventPublisher is null.
Code:
#Bean
#ServiceActivator(inputChannel = "a04A08OutgoingChannel")
public MessageHandler a04A08OutgoingGate() {
final TcpOutboundGateway gate = new TcpOutboundGateway();
// Connection configured in client mode to send the message over the TCP socket
// and wait for acknowledgement
gate.setConnectionFactory(connectionFactory.connectionFactory(host, port));
gate.setReplyChannelName("a04A08ReplyToString");
gate.setRemoteTimeout(60_000);
return gate;
}
#Transformer(inputChannel = "a04A08ReplyToString")
public String transform(byte[] bytes) {
String reply = new String(bytes);
log.debug("transform - a04A08ReplyToString channel " + reply);
return new String(bytes);
}
public String outgoingMessage(String message) {
String reply = null;
log.info("Message being Sent : " + message);
try {
// Send the message to the TCP socket and wait for acknowledgement
reply = a04a08OutgoingGateway.sendMessage(message);
} catch (ConnectException e) {
log.error(e.getMessage(),e);
}
log.info("Acknowledgement received : " + reply);
return reply;
}
ConnectionFactory.java:
public AbstractClientConnectionFactory connectionFactory(String host, int port) {
final AbstractClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory(host, port);
connectionFactory.setSerializer(customDeserializer);
connectionFactory.setDeserializer(customDeserializer);
//connectionFactory.setSoKeepAlive(true);
connectionFactory.setSingleUse(true);// This property when set to false ensures that one shared connection is used for all
// request/replies and each caller blocks waiting for the socket
return connectionFactory;
}
Edit 1 : Included CustomDeserializer.java
#Override
public void serialize(String object, OutputStream outputStream) throws IOException {
log.info("[Serialize] Serializing data : length ==> " + object.length());
outputStream.write(object.getBytes());
log.info("[Serialize] data posted to stream");
}
#Override
public byte[] deserialize(InputStream inputStream) throws IOException {
log.info("[Deserialize] De-Serializing data");
BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer stringbuffer = new StringBuffer();
while (true) {
int value = input.read();
if (value == 28) {
break;
} else {
if (value != -1) {
stringbuffer.append((char) value + "");
} else {
break;
}
}
}
log.info("[deserialize.readFromSocket()]: " + stringbuffer.toString());
return stringbuffer.toString().getBytes();
}
The TCP server is able to receive the messages sent by the TCP client. [Note: TCP server is a different system and not maintained by us].I have 2 queries.
Will this warning have any impact? Can anyone elaborate on the warning? Even when the warnings are seen the messages from TCP client are sent to TCP server without any issues.
We faced below issue (Caused by: org.springframework.messaging.MessagingException: Exception while awaiting reply; nested exception is java.net.SocketTimeoutException: Read timed out) in production recently. When we faced the below exception, telnet to the server port worked but the messages were not received by the server. The issue was automatically resolved when the TCP server was restarted. My question : Is this issue related to the warning in point #1. These warnings are seen even on normal days when the messages are sent to the server without any issues.
Error logs
P.S: I also checked the post : No publisher available to publish TcpConnectionOpenEvent / TcpConnectionCloseEvent
It is not related; sounds like a server problem if restarting it solves it.
The connection factory must be declared as a #Bean so that spring can inject the event publisher.
My question is simple.
I want to know how to fix port client has.
According to Eclipse documents and IBM's, User has to fix broker address(this is absolutely natural). But There are no mentions about way of how to fix client site port.
https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.javadoc.doc/WMQMQxrClasses/com/ibm/micro/client/mqttv3/MqttClient.html
MQTT must be also on TCP Layer, so I think it's possible to fix port.
If you have ideas, let me know.
Thanks
Under normal circumstance you don't set the source port for TCP connections, you just let the OS pick a random free port.
If you fix the source port then you can only ever run 1 instance of the client at a time on a given machine and if you get a connection failure you have to wait for the TCP stack to free that socket up again before you can reconnect.
If for some reason you REALLY NEED to fix the source port then you could probably write a custom javax.net.SocketFactory implementation that you can hard code the source port. Then pass this in as part of the MQTTConnectOptions object, but again I'm really struggling to come up with a reason this is a good idea.
You don't specify the client's port, as it is choosen by the OS, just as with any client to server connection, like you don't need to do that with a HTTP connection either.
You specify the IP address and port of the MQTT broker in the URL you pass in the form of tcp://<address>:<port>, for example tcp://localhost:4922.
The code below shows how I connect a Paho client in an OSGi context, where all connections parameters are retrieved from the bundle context.
private void configureMqtt(BundleContext context) throws IOException, MqttException {
String broker = context.getProperty("mqtt.broker");
if (broker == null) {
throw new ServiceException("Define mqtt.broker");
}
String client = context.getProperty("mqtt.clientname");
if (client == null) {
throw new ServiceException("Define mqtt.clientname");
}
String dir = context.getProperty("mqtt.persistence");
if (dir == null) {
dir = "mqtt";
};
File directory = context.getDataFile(dir);
directory.mkdirs();
logger.config(() -> String.format("MQTT broker: %s, clientname: %s persistence: %s", broker, client, directory.getAbsolutePath()));
connectOptions = new MqttConnectOptions();
connectOptions.setWill(GARAGE + "/door", new byte[0], 0, true);
String ka = context.getProperty("mqtt.keepalive");
if (ka != null) {
connectOptions.setKeepAliveInterval(Integer.valueOf(ka));
}
persistence = new MqttDefaultFilePersistence(directory.getCanonicalPath());
mqttClient = new MqttAsyncClient(broker, client, persistence);
mqttClient.setCallback(this);
connect();
}
private void connect() {
logger.fine("Connecting to MQTT broker");
try {
IMqttToken token = mqttClient.connect(connectOptions);
IMqttActionListener listener = new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
logger.log(Level.INFO, "Connected to MQTT broker");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
logger.log(Level.WARNING, "Could not connect to MQTT broker, retrying in 3 seconds", exception);
service.schedule(this::connect, 3, TimeUnit.SECONDS);
}
};
token.setActionCallback(listener);
} catch (MqttException e) {
logger.log(Level.SEVERE, "Cannot reconnect to MQTT broker, giving up", e);
}
}
I am trying to have chat in my application using Phoenix channels. I have a web client and and an Android client. Right now it is working correctly on the web. I am having an issue with the Android side.
It is able to receive messages pushed to the channel, but it wont send any out. When I try to push a message I get the following exceptions thrown:
java.net.SocketTimeoutException: timeout exception
java.lang.IllegalStateException: Another message writer is active. Did you call close()?
My chat channel
defmodule GoodApi2.ChatChannel do
use Phoenix.Channel
intercept(["chat_send"])
def join("chat:"<> _room_code, _message, socket) do
{:ok, socket}
end
def handle_in("chat_send", message, socket) do
broadcast! socket, "chat_send", message
{:noreply, socket}
end
def handle_out("chat_send", payload, socket) do
push socket, "new_message", payload
{:noreply, socket}
end
end
On the Android app creating the channel
try{
socket = new Socket("ws:"+ApiUtils.BASE.toString()+"socket/websocket");
socket.connect();
channel = socket.chan("chat:"+chatName, null);
channel.join()
.receive("ok", new IMessageCallback() {
#Override
public void onMessage(Envelope envelope) {
System.out.println("IGNORE");
}
});
}
catch (IOException e) {
System.out.println("error connecting to chat");
e.printStackTrace();
}
On the Android app pushing to the channel
public void sendMessage(final String message){
ObjectNode node = new ObjectNode(JsonNodeFactory.instance)
.put("sender", email)
.put("sender_name", userName)
.put("content", message);
try{
channel.push("chat_send", node);
}
catch (Exception e){
Log.e("message failed to send", message);
}
}
Have implemented gcm ccs for chat module and i am able to send and receive messages. Below is the main connection module,
config = XMPPTCPConnectionConfiguration.builder()
.setServiceName("gcm-pesu.googleapis.com")
.setPort(GCM_PORT)
.setHost(GCM_SERVER)
.setCompressionEnabled(false)
.setConnectTimeout(30000)
.setSecurityMode(SecurityMode.ifpossible)
.setSendPresence(false)
.setSocketFactory(SSLSocketFactory.getDefault())
.build();
connection = new XMPPTCPConnection(config);
connection.connect();
Roster roster = Roster.getInstanceFor(connection);
roster.setRosterLoadedAtLogin(false);
connection.addConnectionListener(new LoggingConnectionListener());
// Handle incoming packets
connection.addAsyncStanzaListener(new MyStanzaListener(), new MyStanzaFilter());
// Log all outgoing packets
connection.addPacketInterceptor(new MyStanzaInterceptor(), new MyStanzaFilter());
connection.login(mProjectId + "#gcm.googleapis.com", mApiKey);
logger.info("logged in: " + mProjectId);
PingManager pm = PingManager.getInstanceFor(connection);
pm.setPingInterval(300);
pm.pingMyServer();
pm.registerPingFailedListener(new PingFailedListener() {
#Override
public void pingFailed() {
connection.disconnect();
logger.error("GCM CCS, Ping failed !!");
}
});
The problem i am running into is not receiving any message from GCM, sent by client device after a while. Though, the heartbeat looks normal and i do get pong from GCM even in that case. Is it something to do with SSL ?
Have handled connection draining case as follows,
String controlType = (String) jsonObject.get("control_type");
volatile boolean connectionDraining = false;
if ("CONNECTION_DRAINING".equals(controlType)) {
connectionDraining = true;
try {
connection.disconnect();
connect();
connectionDraining = false;
} catch (Exception e) {
logger.error("Error establishing new connection after draining ", e);
}
}
Implemented queue of channels when one of it is draining.
private Deque<Channel> channels;
protected void handleControlMessage(Map<String, Object> jsonObject) {
logger.info("Control message : " + jsonObject);
String controlType = (String) jsonObject.get("control_type");
if ("CONNECTION_DRAINING".equals(controlType)) {
connectionDraining = true;
}
}
Create new channel while sending message
public void sendDownstreamMessage(String jsonRequest) {
Channel channel = channels.peekFirst();
try {
if (channel.connectionDraining) {
synchronized (channels) {
channel = channels.peekFirst();
if (channel.connectionDraining) {
channels.addFirst(connect());
channel = channels.peekFirst();
}
}
}
channel.send(jsonRequest);
} catch (Exception e) {
logger.error("Message not sent. Error in connecting :", e);
}
}
GCM will take care of closing the other. This resolved the issue.
I believe you're facing a common case using gcm css that is not very visible in the documentation.
If you look in the doc, Control Messages you'll read:
Periodically, CCS needs to close down a connection to perform load balancing. Before it closes the connection, CCS sends a CONNECTION_DRAINING message to indicate that the connection is being drained and will be closed soon. "Draining" refers to shutting off the flow of messages coming into a connection, but allowing whatever is already in the pipeline to continue. When you receive a CONNECTION_DRAINING message, you should immediately begin sending messages to another CCS connection, opening a new connection if necessary. You should, however, keep the original connection open and continue receiving messages that may come over the connection (and ACKing them)—CCS handles initiating a connection close when it is ready.
I am trying to learn MQTT and have been playing around with it. I've written a client for publishing and a client for subscribing (see below).
If I run the subscribe client and then run the publish client (while subscribe is running), then everything works fine. My subscribe client receives the messages published to the topic correctly.
However, if I run the publish client first (ie. I publish a message to a topic) and then I run the subscribe client, I receive no messages.
In other words, if I connect with the sub client first and then publish messages with the pub client while sub client is connected, everything works fine. However, if I publish a message first, and then connect with my sub client, I receive no messages. My understanding is that I should receive the messages that are present on the topic once I connect with a client and subscribe to the topic.
I found what seems a similar issue: Cannot receive already published messages to subscribed topic on mqtt paho, although that case seems a little different. I've tried changing different QoS setting or cleanSession flag, but that didn't resolve the issue.
Any help would be appreciated!
Publish Client:
public class MQTT_Client_Pub implements MqttCallback{
MqttClient client;
public static void main(String[] args) {
new MQTT_Client_Pub().mqttPub();
}
public void mqttPub(){
try {
this.setConnection();
// Connect
client.connect();
// Create new message
MqttMessage message = new MqttMessage();
message.setPayload("A single test message from b112358".getBytes());
message.setQos(0);
// Publish message to a topic
System.out.println("Publishing a message.");
client.publish("pahodemo/test/b112358", message);
// Disconnect
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
public void setConnection(){
// Client
try{
client = new MqttClient("tcp://iot.eclipse.org:1883", "mqtt_test_b112358_pub");
} catch (MqttException e) {
e.printStackTrace();
}
// Connection Options
MqttConnectOptions options = new MqttConnectOptions();
// Set the will
options.setWill("pahodemo/clienterrors", "CRASHED - CONNECTION NOT CLOSED CLEANLY".getBytes(),2,true);
// Set Callback
client.setCallback(this);
}
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("Message delivered to the broker.");
}
public void messageArrived(String topic, MqttMessage message) throws Exception {}
public void connectionLost(Throwable cause) {}
}
Subscribe Client:
public class MQTT_Client_Sub implements MqttCallback{
MqttClient client;
public static void main(String[] args) {
new MQTT_Client_Sub().mqttSub();
}
public void mqttSub(){
try {
// Set connection
this.setConnection();
// Connect
client.connect();
// Subscribe
client.subscribe("pahodemo/test/b112358", 0);
// Disconnect
// client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
}
public void setConnection(){
try {
// Client
client = new MqttClient("tcp://iot.eclipse.org:1883", "mqtt_test_b112358_sub");
} catch (MqttException e) {
e.printStackTrace();
}
// Connection Options
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
// Set the will
options.setWill("pahodemo/clienterrors", "CRASHED - CONNECTION NOT CLOSED CLEANLY".getBytes(),2,true);
client.setCallback(this);
}
public void deliveryComplete(IMqttDeliveryToken token) {}
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("Message Arrived: " + message.getPayload() + " on tipic: " + topic.getBytes());
}
public void connectionLost(Throwable cause) {}
}
Messages published before the subscriber connects and subscribes will only be delivered under the following 2 situations
When the messages was published as retained. This means the last message on that topic will be delivered to a new subscriber at the point of subscription. This will only deliver the last message.
If the client had been previously connected and subscribed, then been disconnected. A message is then published and the client connects again with cleansession = false. (and when the subscription is at QOS1/2)
This may help: http://www.thingsprime.com/?p=2897