Netty NioSocketChannel got broken message on multithread write - java

I'm writing my own simple game server using Netty 4.0.25.
I want to support msgpack binary data so every message send/receive on a channel always encoded/decoded by msgpack.
my server:
bossGroup = new NioEventLoopGroup(4);
workerGroup = new NioEventLoopGroup(4);
bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.handler(new LoggingHandler(LogLevel.DEBUG));
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("frameEncoder", new LengthFieldPrepender(4));
ch.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
ch.pipeline().addLast(new NettyNioBinaryTcpSession());
}
});
// Bind and start to accept incoming connections.
channelFuture = bootstrap.bind(this.getGatewayConfig().getHost(), this.getGatewayConfig().getPort());
and client:
group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), getServerAddress().getHost(), getServerAddress()
.getPort()));
}
p.addLast("frameEncoder", new LengthFieldPrepender(4));
p.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
p.addLast(new SessionClientHandler());
}
});
// Start the client.
channelFuture = bootstrap.connect(getServerAddress().getHost(), getServerAddress().getPort());
everything work seem to be ok until I try to send 1000 message/second from client and echo it back from server. My server working properly with no error logged, but at my client, I got:
2015-03-04 20:20:22.173 [SocketReceivingWorker-3] WARN com.puppet.client.io.SocketReceivingHandler (SocketReceivingHandler.java:71) - got pong message, but message id not found���� -> length: 4 -> base 64: 1//z/Q==
Each message send from client to server and echo back has 12 bytes of size.
I don't know why, and I have tried to research for a few day but nothing found.
Thanks in advance,
UPDATE: SocketReceivingHandler.java:
package com.puppet.client.io;
import static org.msgpack.template.Templates.TByteArray;
import static org.msgpack.template.Templates.TString;
import static org.msgpack.template.Templates.tMap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Map;
import org.msgpack.MessagePack;
import org.msgpack.MessageTypeException;
import org.msgpack.template.Template;
import org.msgpack.unpacker.Unpacker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lmax.disruptor.WorkHandler;
import com.puppet.client.PuppetClient;
import com.puppet.client.exceptions.MessageUnrecognizedException;
import com.puppet.common.Fields;
import com.puppet.common.PuCommand;
import com.puppet.common.PuEventType;
import com.puppet.common.message.concrete.PingMessage;
import com.puppet.eventdriven.impl.BaseEvent;
public class SocketReceivingHandler implements WorkHandler<SocketReceivingEvent> {
private static final Logger logger = LoggerFactory.getLogger(SocketReceivingHandler.class);
private static final MessagePack msgpack = new MessagePack();
private static Template<Map<String, byte[]>> stringToBytesMapTemplate = tMap(TString, TByteArray);
private PuppetClient client;
public SocketReceivingHandler(PuppetClient client) {
this.client = client;
}
#Override
public void onEvent(SocketReceivingEvent event) throws Exception {
ByteArrayInputStream byteArrInputStream = new ByteArrayInputStream(event.getData());
Unpacker unpacker = msgpack.createUnpacker(byteArrInputStream);
try {
Map<String, byte[]> request = unpacker.read(stringToBytesMapTemplate);
PuCommand command = PuCommand.fromId(request.get(Fields.COMMAND));
if (command != null) {
handleCommand(command, request.get(Fields.DATA));
} else {
throw new MessageUnrecognizedException();
}
} catch (MessageTypeException mtEx) {
logger.debug("message error: " + new String(event.getData()) + " -> length " + event.getData().length
+ " -> base64: " + Base64.getEncoder().encodeToString(event.getData()));
throw new MessageUnrecognizedException(mtEx);
}
}
private void handleCommand(PuCommand command, byte[] data) throws IOException {
switch (command) {
case PONG:
this.client.dispatchEvent(new BaseEvent(PuEventType.PONG, "data", data));
Long startTime = PingMessage.getTimeForMessageId(data);
PingMessage.removeTimeForMessageId(data);
if (startTime != null) {
this.client.dispatchEvent(new BaseEvent(PuEventType.PING_PONG, "delay", System.nanoTime() - startTime));
} else {
logger.warn("got pong message, but message id not found" + new String(data) + " -> length: "
+ data.length + " -> base 64: " + Base64.getEncoder().encodeToString(data));
}
break;
default:
logger.debug("unrecognized command: " + command);
break;
}
}
}
event.getData() ==> data read from socket and got in channelRead menthod.

This is my mistake, ping-pong message's id instead of auto increment int, I use random bytes. sometimes that id is duplicated... then that error occurs.
Thanks!

Related

High concurrent client with NIO

I'm writing a tool that will generate a high amount of HTTP calls against a webserver. At this moment I'm interested on how many requests can I make per second. I'm not interested now of the result of those requests.
I'm measuring the time spent to send 1k requests against google.com and I get 69 milliseconds :
but when I'm sniffing the traffic with WireShark I see that sending all the GET requests is taking almost 4 seconds:
start of the calls
end of the calls
Tool has been run from IntelliJ on Windows 10, I7 1.8 Ghz, 32 GB of RAM.
My question is: why I have this difference? Sending 1k HTTP GET requests should be quick, but it takes almost 4 seconds. What I'm doing wrong here?
The code above is only for testing purposes and it's quite ugly, so bear with me. Also I'm not quite familiar with NIO.
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class UJPPHighTrafficClient {
public static final Logger logger = LoggerFactory.getLogger(UJPPHighTrafficClient.class);
public static final int iterations = 1000;
public static void main(String[] args) {
doStartClient();
}
private static void doStartClient() {
logger.info("starting the client");
UJPPHighTrafficExecutor executor = new UJPPHighTrafficExecutor();
StopWatch watch = new StopWatch();
watch.start();
for (int i = 0; i < iterations; i++) {
executor.run();
}
watch.stop();
logger.info("Run " + iterations + " executions in " + watch.getTime() + " milliseconds");
}
}
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.impl.nio.DefaultHttpClientIODispatch;
import org.apache.http.impl.nio.pool.BasicNIOConnPool;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.nio.protocol.*;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.protocol.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.concurrent.atomic.AtomicInteger;
public class UJPPHighTrafficExecutor {
private final Logger logger = LoggerFactory.getLogger("debug");
public static ConnectingIOReactor requestsReactor = null;
private static BasicNIOConnPool clientConnectionPool = null;
public static HttpAsyncRequester clientRequester = null;
public static Thread runnerThread = null;
private static AtomicInteger counter = null;
public static final int cores = Runtime.getRuntime().availableProcessors() * 2;
public UJPPHighTrafficExecutor() {
counter = new AtomicInteger();
counter.set(0);
initializeConnectionManager();
}
public void initializeConnectionManager() {
try {
requestsReactor =
new DefaultConnectingIOReactor(IOReactorConfig.
custom().
setIoThreadCount(cores).
build());
clientConnectionPool = new BasicNIOConnPool(requestsReactor, ConnectionConfig.DEFAULT);
clientConnectionPool.setDefaultMaxPerRoute(cores);
clientConnectionPool.setMaxTotal(100);
clientRequester = initializeHttpClient(requestsReactor);
} catch (IOReactorException ex) {
logger.error(" initializeConnectionManager " + ex.getMessage());
}
}
private HttpAsyncRequester initializeHttpClient(final ConnectingIOReactor ioReactor) {
// Create HTTP protocol processing chain
HttpProcessor httpproc = HttpProcessorBuilder.create()
// Use standard client-side protocol interceptors
.add(new RequestContent(true)).
add(new RequestTargetHost()).
add(new RequestConnControl())
.add(new RequestExpectContinue(true)).
build();
// Create HTTP requester
HttpAsyncRequester requester = new HttpAsyncRequester(httpproc);
// Create client-side HTTP protocol handler
HttpAsyncRequestExecutor protocolHandler = new HttpAsyncRequestExecutor();
// Create client-side I/O event dispatch
final IOEventDispatch ioEventDispatch =
new DefaultHttpClientIODispatch(protocolHandler, ConnectionConfig.DEFAULT);
// Run the I/O reactor in a separate thread
runnerThread = new Thread("Client") {
#Override
public void run() {
try {
ioReactor.execute(ioEventDispatch);
} catch (InterruptedIOException ex) {
logger.error("Interrupted", ex);
} catch (IOException e) {
logger.error("I/O error", e);
} catch (Exception e) {
logger.error("Exception encountered in Client ", e.getMessage(), e);
}
logger.info("Client shutdown");
}
};
runnerThread.start();
return requester;
}
public void run() {
HttpHost httpHost = new HttpHost("google.com", 80, "http");
final HttpCoreContext coreContext = HttpCoreContext.create();
ProtocolVersion ver = new ProtocolVersion("HTTP", 1, 1);
BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("GET", "/", ver);
clientRequester.execute(new BasicAsyncRequestProducer(httpHost, request), new BasicAsyncResponseConsumer(),
clientConnectionPool, coreContext,
// Handle HTTP response from a callback
new FutureCallback<HttpResponse>() {
#Override
public void completed(final HttpResponse response) {
logger.info("Completed " + response.toString());
checkCounter();
}
#Override
public void failed(final Exception ex) {
logger.info("Failed " + ex.getMessage());
checkCounter();
}
#Override
public void cancelled() {
logger.info("Cancelled ");
checkCounter();
}
});
}
private void checkCounter() {
counter.set(counter.get() + 1);
if (counter.get() == UJPPHighTrafficClient.iterations) {
try {
requestsReactor.shutdown();
} catch (Exception ex) {
}
}
}
}
You code is timing how long it is to set up 1000 iterations of http connection, and not the time to complete those connections many of which are still running 3-4 seconds later. To see a more accurate figure put a local field t0 into UJPPHighTrafficExecutor:
public class UJPPHighTrafficExecutor {
long t0 = System.nanoTime();
...and then checkCounter() can print a time for completing all iterations:
private void checkCounter() {
counter.set(counter.get() + 1);
if (counter.get() == UJPPHighTrafficClient.iterations) {
try {
requestsReactor.shutdown();
} catch (Exception ex) {
}
long t1 = System.nanoTime();
System.out.println("ELAPSED MILLIS: ~"+TimeUnit.NANOSECONDS.toMillis(t1-t0));
}
}
This will print a much larger number for 1000 iterations:
ELAPSED MILLIS: ~xxxx
Note that counter.set(counter.get() + 1) is not safe way to increment AtomicInteger , remove the line and increment inside the if statement:
if (counter.incrementAndGet() == UJPPHighTrafficClient.iterations)

SNMP4j with snmpv3 response and error is null

I'm using snmp4j 3.4.2 inside my java application (full code below)
I'm trying to execute a snmpget with snmpv3, security DES and auth MD5 and custom OID (python script, which is executed by snmp's extend funtionality). To create better understanding I used SnmpConstants.sysUpTime in the example below.
The SNMP resource has this user configured:
defSecurityName demo
defSecurityLevel authPriv
defAuthType MD5
defPrivType DES
defAuthPassphrase pass
defPrivPassphrase pass
I'm already using this user and resource to successfully perform the snmpget with python (pysnmp) and bash (snmpget), so I can definitely tell that my setup works and the java code is the problem.
I have two java classes (Listener.java and ServerStatusHelper.java)
Listener.java contains main and calls the snmpGet inside ServerStatusHelper.java, other code of Listener is excluded as its not neccessary.
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.PrivDES;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.VariableBinding;
public class Listener {
public static void main(String[] args) {
ServerStatusHelper agent = new ServerStatusHelper("host.tld", "udp", 161, "demo", "demo",
"pass", "pass", new AuthMD5(), new PrivDES(), true);
try {
agent.startAgent();
ResponseEvent response = agent.snmpGetOperation(SnmpConstants.sysUpTime);
if (response != null) {
System.out.println(
"response null - error: "+ response.getError() +
"peerAddress: " + response.getPeerAddress() +
"source: " + response.getSource().toString() +
"request: " + response.getRequest());
}
} catch (
IOException e) {
e.printStackTrace();
}
}
}
ServerStatusHelper.java
import java.io.IOException;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.UserTarget;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.AuthGeneric;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.PrivacyGeneric;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TransportIpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
public class ServerStatusHelper {
private Address nmsIP;
private String user;
private String securityName;
private String privacyPassword;
private String authorizationPassword;
private AuthGeneric authProtocol;
private PrivacyGeneric privacyProtocol;
private String protocol;
private boolean encryption;
private long timeOut = 1000;
private int noOfRetries = 10;
private Snmp snmp;
private UserTarget target;
private CommunityTarget v1target;
ServerStatusHelper(String ip, String protocol, int snmpPort, String username, String securityName,
String privacyPassword, String authPassowrd, AuthGeneric authProtocol, PrivacyGeneric privacyProtocol,
boolean encryption) {
nmsIP = GenericAddress.parse(protocol + ":" + ip + "/" + snmpPort);
System.out.println("NMS IP set : " + nmsIP.toString());
this.protocol = protocol;
this.user = username;
this.securityName = securityName;
this.privacyPassword = privacyPassword;
this.authorizationPassword = authPassowrd;
this.authProtocol = authProtocol;
this.privacyProtocol = privacyProtocol;
this.encryption = encryption;
SecurityProtocols.getInstance().addAuthenticationProtocol(new AuthMD5());
SecurityProtocols.getInstance().addPrivacyProtocol(new PrivDES());
}
public void startAgent() throws IOException {
if (snmp == null) {
TransportMapping<? extends TransportIpAddress> transport = null;
if (protocol.equalsIgnoreCase("udp")) {
System.out.println("UDP Protocol selected.");
transport = new DefaultUdpTransportMapping();
} else {
System.out.println("TCP Protocol selected.");
transport = new DefaultTcpTransportMapping();
}
snmp = new Snmp(transport);
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
transport.listen();
snmp.getUSM().addUser(new OctetString(user),
new UsmUser(new OctetString(securityName), authProtocol.getID(),
new OctetString(authorizationPassword), privacyProtocol.getID(),
new OctetString(privacyPassword)));
if (encryption)
target = createUserTarget();
else
v1target = createUserTargetWithoutEncryption();
}
}
public ResponseEvent snmpSetOperation(VariableBinding[] vars) throws IOException {
PDU setPdu = new ScopedPDU();
for (VariableBinding variableBinding : vars) {
setPdu.add(variableBinding);
}
return snmp.send(setPdu, target);
}
public ResponseEvent snmpGetOperation(OID oid) throws IOException {
if (encryption) {
PDU getPdu = new ScopedPDU();
getPdu.add(new VariableBinding(oid));
getPdu.setType(ScopedPDU.GET);
return snmp.get(getPdu, target);
} else {
PDU getPdu = new PDU();
getPdu.add(new VariableBinding(oid));
getPdu.setType(PDU.GET);
return snmp.get(getPdu, v1target);
}
}
private UserTarget createUserTarget() {
UserTarget target = new UserTarget();
target.setAddress(nmsIP);
target.setRetries(noOfRetries);
target.setTimeout(timeOut);
target.setVersion(SnmpConstants.version3);
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target.setSecurityName(new OctetString(securityName));
return target;
}
private CommunityTarget createUserTargetWithoutEncryption() {
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
target.setAddress(nmsIP);
target.setRetries(noOfRetries);
target.setTimeout(timeOut);
target.setVersion(SnmpConstants.version1);
return target;
}
public long getTimeOut() {
return timeOut;
}
public void setTimeOut(long timeOut) {
this.timeOut = timeOut;
}
public int getNoOfRetries() {
return noOfRetries;
}
public void setNoOfRetries(int noOfRetries) {
this.noOfRetries = noOfRetries;
}
}
The execution of the program exits with
NMS IP set : **IPREMOVED**/161
UDP Protocol selected.
response null - error: nullpeerAddress: **IPREMOVED**/161source: org.snmp4j.Snmp#e580929 request: GET[{contextEngineID=80:00:1f:88:80:5e:2e:49:07:2f:68:44:57:00:00:00:00, contextName=}, requestID=588252045, errorStatus=0, errorIndex=0, VBS[1.3.6.1.2.1.1.3.0 = Null]]
Anyone has an idea what I'm doing wrong?
Edit:
From the servers syslog I can see, that the request arrives at the resource:
Jul 31 11:52:46 loadbalancer snmpd[1219]: Connection from UDP: [IP REMOVED]:54734->[IP REMOVED]:161
Jul 31 11:52:46 loadbalancer snmpd[1219]: Connection from UDP: [IP REMOVED]:54734->[IP REMOVED]:161
#i-shm I think you are doing everything ok.
The only problem in your code could be just the line in which you evaluate the response variable. Your are indicating response != null when it should be actually response == null. I mean:
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.PrivDES;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.VariableBinding;
public class Listener {
public static void main(String[] args) {
ServerStatusHelper agent = new ServerStatusHelper("host.tld", "udp", 161, "demo", "demo",
"pass", "pass", new AuthMD5(), new PrivDES(), true);
try {
agent.startAgent();
ResponseEvent event = agent.snmpGetOperation(SnmpConstants.sysUpTime);
final PDU response = event.getResponse();
if (response == null) {
System.out.println(
"response null - error: "+ event.getError() +
"peerAddress: " + event.getPeerAddress() +
"source: " + event.getSource().toString() +
"request: " + event.getRequest());
} else {
System.out.println("Response PDU:" + response.toString());
// Process the response as you need, maybe something like this:
long sysUpTime = response.get(0).getVariable().toLong();
// You can find relevant information in the javadocs of the library:
// https://agentpp.com/doc/snmp4j/index.html?org/snmp4j/package-summary.html
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
This is why you do not receive errors in the java code and your syslog indicates that the requests were actually sent.

Message MQTT not receive in subscribe client

I'm working on MQTT protocol and I try to publish and subscribe with 2 distincts Java applications.
My first application is "Publish". I'm publish on a MQTT server a message.
My second application is "Subscribe". I'm subscribe to a topic and try to receive the message. But I never receive the message.
When I run the 2 applications, I begin with the "Subscribe" application and after I run the "Publish" application. When the "Publish" application begin, I lose my connection to the "Subscribe" application and I can't receive my message.
In the "Subscribe" application, my method messageArrived() is never called by client.setCallback(this). (See the code below).
Here is my 2 code application :
Publish Application :
Class PubClient :
package publishclient;
import java.util.Random;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class PubClient implements MqttCallback {
MqttClient client;
MqttConnectOptions connOpt;
Random rand = new Random();
int nbRandom = 0;
int valMax =151, valMin = 40;
public PubClient() throws MqttException {
String broker = "tcp://88.177.147.17:1883"; // Adress MQTT Server
String clientId = "0bdd-4445-82f3-928f8ddb1887"; // ClientID
String topic1f = "ApplicationRio/capteur"; // Topic
int QoSserveur = 2;
try {
String uuid = "ac8da3c6-0bdd-4445-82f3-928f8ddb3294";
MemoryPersistence persistence = new MemoryPersistence();
// Create 2 objects : client and connOpt
client = new MqttClient(broker, clientId, persistence);
connOpt = new MqttConnectOptions();
connOpt.setCleanSession(true);
client.setCallback(this);
// Connection to MQTT server
System.out.println("Connexion a : " + broker + " Publisher");
client.connect(connOpt);
//Create random number for my message
nbRandom = valMin + rand.nextInt(valMax-valMin);
System.out.println("nb aleatoire = " + nbRandom);
String messageAEnvoyer = uuid + "//" + nbRandom;
System.out.println("Message a envoyer : " + messageAEnvoyer);
MqttMessage message = new MqttMessage();
message.setPayload(messageAEnvoyer.getBytes());
message.setQos(QoSserveur);
client.publish(topic1f, message);
} catch(MqttException e) {
e.printStackTrace();
}
}
#Override
public void connectionLost(Throwable thrwbl) {System.out.println("Perdue connexion");}
#Override
public void messageArrived(String string, MqttMessage mm) throws Exception {
System.out.println("Message recu est : "+ new String(mm.getPayload()));}
#Override
public void deliveryComplete(IMqttDeliveryToken imdt) {
System.out.println("Message delivre au broker");
}
}
The main (Publish) :
package publishclient;
import org.eclipse.paho.client.mqttv3.MqttException;
public class PublishClient {
public static void main(String[] args) throws MqttException {
PubClient publieur = new PubClient();
}
The "subscribe" application :
Class SubClient :
package subscribeclient;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
public class SubClient implements MqttCallback {
MqttClient clientsub;
MqttConnectOptions connOpt;
public SubClient() throws MqttException{
String broker = "tcp://88.177.147.17:1883"; // Adress MQTT Server
String clientId = "0bdd-4445-82f3-928f8ddb1887"; // ClientID
String topic1f = "ApplicationRio/capteur"; // Topic
int QoSserveur = 2;
try{
// Create 2 objects : client and connOpt
clientsub = new MqttClient(broker, clientId);
connOpt = new MqttConnectOptions();
connOpt.setCleanSession(false);
connOpt.setKeepAliveInterval(30);
clientsub.setCallback(this);
// Connection to MQTT Server
System.out.println("Connexion a : " + broker + " Subscriber");
clientsub.connect(connOpt);
clientsub.subscribe(topic1f,QoSserveur);
} catch(MqttException e){
e.printStackTrace();
}
}
#Override
public void connectionLost(Throwable thrwbl) {
System.out.println("Connexion perdue");
}
#Override
public void messageArrived(String string, MqttMessage message) throws Exception {
System.out.println("Le message recu est : " + new String(message.getPayload()));
}
#Override
public void deliveryComplete(IMqttDeliveryToken imdt) {
System.out.println("Message arrive");
}
}
The main (Subscribe) :
package subscribeclient;
import org.eclipse.paho.client.mqttv3.MqttException;
public class SubscribeClient {
public static void main(String[] args) throws MqttException {
SubClient subscriber = new SubClient();
}
}
My 2 applications need to run in the same time, and I don't need to disconnect because I run applications all the time.
So, have you got an idea of why my "Subscribe Client" disconnect when I run the "Publish Client" and why I can't receive my message on my "Subscribe Message" ?
I use org.eclipse.paho.client.mqttv3-1.0.2.jar for the library for MQTT.
Client IDs have to be unique between ALL clients. You have used the same client ID for the publisher and subscriber so the broker will kick the subscriber off when the publisher connects.

Message not being sent when Akka actor is killed using DeathWatch

I'm attempting to send a message when an actor is killed.
This is based on Akka deathwatch documentation :
http://doc.akka.io/docs/akka/2.3.6/java/untyped-actors.html#deathwatch-java
In serviceActor I'm awaiting a "kill" message but I'm never actually sending this message. So to receive the message in ServiceActor I use :
else if (msg instanceof Terminated) {
final Terminated t = (Terminated) msg;
if (t.getActor() == child) {
lastSender.tell(Msg.TERMINATED, getSelf());
}
} else {
unhandled(msg);
}
I've set the duration to 10 milliseconds :
Duration.create(10, TimeUnit.MILLISECONDS)
But the message Msg.TERMINATED is never received in onReceive method :
#Override
public void onReceive(Object msg) {
if (msg == ServiceActor.Msg.SUCCESS) {
System.out.println("Success");
getContext().stop(getSelf());
} else if (msg == ServiceActor.Msg.TERMINATED) {
System.out.println("Terminated");
} else
unhandled(msg);
}
How can I send a message to HelloWorld when ServiceActor fails ?
Entire code :
package terminatetest;
import akka.Main;
public class Launcher {
public static void main(String args[]) {
String[] akkaArgsArray = new String[1];
akkaArgsArray[0] = "terminatetest.HelloWorld";
Main.main(akkaArgsArray);
}
}
package terminatetest;
import java.util.concurrent.TimeUnit;
import scala.concurrent.duration.Duration;
import akka.actor.ActorRef;
import akka.actor.PoisonPill;
import akka.actor.Props;
import akka.actor.UntypedActor;
public class HelloWorld extends UntypedActor {
#Override
public void preStart() {
int counter = 0;
akka.actor.ActorSystem system = getContext().system();
final ActorRef greeter = getContext().actorOf(
Props.create(ServiceActor.class), String.valueOf(counter));
system.scheduler().scheduleOnce(
Duration.create(10, TimeUnit.MILLISECONDS), new Runnable() {
public void run() {
greeter.tell(PoisonPill.getInstance(), getSelf());
}
}, system.dispatcher());
greeter.tell("http://www.google.com", getSelf());
counter = counter + 1;
}
#Override
public void onReceive(Object msg) {
if (msg == ServiceActor.Msg.SUCCESS) {
System.out.println("Success");
getContext().stop(getSelf());
} else if (msg == ServiceActor.Msg.TERMINATED) {
System.out.println("Terminated");
} else
unhandled(msg);
}
}
package terminatetest;
import static com.utils.PrintUtils.println;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.Terminated;
import akka.actor.UntypedActor;
public class ServiceActor extends UntypedActor {
final ActorRef child = this.getContext().actorOf(Props.empty(), "child");
{
this.getContext().watch(child);
}
ActorRef lastSender = getContext().system().deadLetters();
public static enum Msg {
SUCCESS, FAIL, TERMINATED;
}
#Override
public void onReceive(Object msg) {
if (msg instanceof String) {
String urlName = (String) msg;
try {
long startTime = System.currentTimeMillis();
URL url = new URL(urlName);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
System.out.println("Connection successful to " + url);
System.out.println("Content is " + out);
long endTime = System.currentTimeMillis();
System.out.println("Total Time : " + (endTime - startTime) + " milliseconds");
} catch (MalformedURLException mue) {
println("URL Name " + urlName);
System.out.println("MalformedURLException");
System.out.println(mue.getMessage());
mue.printStackTrace();
getSender().tell(Msg.FAIL, getSelf());
} catch (IOException ioe) {
println("URL Name " + urlName);
System.out.println("IOException");
System.out.println(ioe.getMessage());
ioe.printStackTrace();
System.out.println("Now exiting");
getSender().tell(Msg.FAIL, getSelf());
}
}
else if (msg instanceof Terminated) {
final Terminated t = (Terminated) msg;
if (t.getActor() == child) {
lastSender.tell(Msg.TERMINATED, getSelf());
}
} else {
unhandled(msg);
}
}
}
Update :
I'm now initiating the poisonPill from the child actor itself using :
Update to ServiceActor :
if (urlName.equalsIgnoreCase("poisonPill")) {
this.getSelf().tell(PoisonPill.getInstance(), getSelf());
getSender().tell(Msg.TERMINATED, getSelf());
}
Update to HelloWorld :
system.scheduler().scheduleOnce(
Duration.create(10, TimeUnit.MILLISECONDS), new Runnable() {
public void run() {
greeter.tell("poisonPill", getSelf());
}
}, system.dispatcher());
This displays following output :
startTime : 1412777375414
Connection successful to http://www.google.com
Content is ....... (I'veremoved the content for brevity)
Total Time : 1268 milliseconds
Terminated
The poisonPill message is sent after 10 milliseconds and for this example the actor lives for 1268 milliseconds. So why is the actor not terminating when the poisonPill is sent ? Is this because the timings are so short ?
Updated code :
package terminatetest;
import java.util.concurrent.TimeUnit;
import scala.concurrent.duration.Duration;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActor;
public class HelloWorld extends UntypedActor {
#Override
public void preStart() {
int counter = 0;
akka.actor.ActorSystem system = getContext().system();
final ActorRef greeter = getContext().actorOf(
Props.create(ServiceActor.class), String.valueOf(counter));
system.scheduler().scheduleOnce(
Duration.create(10, TimeUnit.MILLISECONDS), new Runnable() {
public void run() {
greeter.tell("poisonPill", getSelf());
}
}, system.dispatcher());
greeter.tell("http://www.google.com", getSelf());
counter = counter + 1;
}
#Override
public void onReceive(Object msg) {
if (msg == ServiceActor.Msg.SUCCESS) {
System.out.println("Success");
getContext().stop(getSelf());
} else if (msg == ServiceActor.Msg.TERMINATED) {
System.out.println("Terminated");
} else
unhandled(msg);
}
}
package terminatetest;
import static com.utils.PrintUtils.println;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import akka.actor.ActorRef;
import akka.actor.PoisonPill;
import akka.actor.UntypedActor;
public class ServiceActor extends UntypedActor {
ActorRef lastSender = getSender();
public static enum Msg {
SUCCESS, FAIL, TERMINATED;
}
#Override
public void onReceive(Object msg) {
if (msg instanceof String) {
String urlName = (String) msg;
if (urlName.equalsIgnoreCase("poisonPill")) {
this.getSelf().tell(PoisonPill.getInstance(), getSelf());
getSender().tell(Msg.TERMINATED, getSelf());
}
else {
try {
long startTime = System.currentTimeMillis();
System.out.println("startTime : "+startTime);
URL url = new URL(urlName);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
System.out.println("Connection successful to " + url);
System.out.println("Content is " + out);
long endTime = System.currentTimeMillis();
System.out.println("Total Time : " + (endTime - startTime) + " milliseconds");
} catch (MalformedURLException mue) {
println("URL Name " + urlName);
System.out.println("MalformedURLException");
System.out.println(mue.getMessage());
mue.printStackTrace();
getSender().tell(Msg.FAIL, getSelf());
} catch (IOException ioe) {
println("URL Name " + urlName);
System.out.println("IOException");
System.out.println(ioe.getMessage());
ioe.printStackTrace();
System.out.println("Now exiting");
getSender().tell(Msg.FAIL, getSelf());
}
}
}
}
}
I think your problem stems from the fact that you only set lastSender once, during construction of the ServiceActor, and you explicitly set it to deadletter. If you want to send a message back to the actor that sent you the String message, then you will need to set lastSender to that sender(). Failure to do so will result in your Msg.TERMINATED always going to deadletter.
EDIT
I see the real issue here now. In the HelloWorld actor, you are sending a PoisonPill to the ServiceActor. The ServiceActor will stop itself as a result, thus stopping the child ref too (as it's a child actor to ServiceActor). At this point, you would think the Terminated message would be delivered to ServiceActor because it explicitly watches child (and it probably does get delivered), but you've already sent a PoisonPill to ServiceActor so it will not process any messages received after that message (which would be the Terminate) so that's why the block:
else if (msg instanceof Terminated) {
is never hit in ServiceActor.
EDIT2
Your actor receives the request to hit google first and receives the "poisonPill" message second (10 milliseconds later). As an actor processes it's mailbox in order, the actor fully processes the request to hit google before it processes the message to stop itself. That's why the actor doesn't stop after 10 milliseconds. You can't stop an actor in the middle of what it's doing.

SMS Receiving using JSMPP sometimes stop

I am using JSMPP from Google to receive SMS messages from SMS Service Centre. Sometimes, my program stops receiving SMS from SMSC, I have to close the program and Re-Open the program. Then Queued SMSes from SMSC starts receive. This happens after some time, like after 7 or 8 hours. Here is the code I'v used
SMPP Init Code
l.info("SMPP Initialization");
SMPPSession s = new SMPPSession();
s.setMessageReceiverListener(new Receive(s));
s.connectAndBind(Settings.smsc_host,Settings.smsc_port, BindType.BIND_TRX,
Settings.smsc_user, Settings.smsc_password,Settings.smsc_msg_setting, TypeOfNumber.UNKNOWN,
NumberingPlanIndicator.UNKNOWN, null, Settings.smsc_timeout);
ProcessSMS.s = s;
l.info("SMPP Initialization Success");
SMS Receive Code
package sms;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.log4j.Logger;
import org.jsmpp.bean.AlertNotification;
import org.jsmpp.bean.DataSm;
import org.jsmpp.bean.DeliverSm;
import org.jsmpp.bean.MessageType;
import org.jsmpp.extra.ProcessRequestException;
import org.jsmpp.session.DataSmResult;
import org.jsmpp.session.MessageReceiverListener;
import org.jsmpp.session.Session;
import processor.ProcessSMS;
public class Receive implements MessageReceiverListener {
private static final ExecutorService pool = Executors.newFixedThreadPool(10);
private static final Logger l = Logger.getLogger(Receive.class);
private Thread thread;
public Receive(){
super();
}
public Receive(Session s){
this();
}
#Override
public DataSmResult onAcceptDataSm(DataSm arg0, Session arg1)
throws ProcessRequestException {
return null;
}
#Override
public void onAcceptAlertNotification(AlertNotification arg0) {
}
#Override
public void onAcceptDeliverSm(DeliverSm arg0)
throws ProcessRequestException {
l.info("Received SMS " + arg0);
if(MessageType.SMSC_DEL_RECEIPT.containedIn(arg0.getEsmClass())){
}else{
pool.submit(new ProcessSMS(arg0));
//thread = new Thread(new ProcessSMS(arg0));
//thread.start();
}
}
}
And here is the state change class
package sms;
import java.io.IOException;
import global.Shared;
import log.SMSCStateLogger;
import org.jsmpp.bean.BindType;
import org.jsmpp.bean.NumberingPlanIndicator;
import org.jsmpp.bean.TypeOfNumber;
import org.jsmpp.extra.SessionState;
import org.jsmpp.session.SMPPSession;
import org.jsmpp.session.Session;
import org.jsmpp.session.SessionStateListener;
import processor.ProcessSMS;
import settings.Settings;
public class StateChange implements SessionStateListener{
private static SMSCStateLogger l = new SMSCStateLogger(StateChange.class);
private Session s;
#Override
public void onStateChange(SessionState arg0, SessionState arg1, Object arg2) {
//arg0 = new State
//arg1 = old State
if(!arg0.isBound() && arg1.isBound()){
int con = Shared.getNextReConnectInterval();
l.info("State changed from " + arg1 + " to " + arg0 + " on " + arg2);
while(true){
l.info("Re Connection in " + con + " ms");
try{
Thread.sleep(con);
}catch(InterruptedException iex){
l.fatal("Re Connection failed due to exception " + iex);
break;
}
s = new SMPPSession();
((SMPPSession) s).setMessageReceiverListener(new Receive(s));
s.addSessionStateListener(new StateChange());
try{
((SMPPSession) s).connectAndBind(Settings.smsc_host,Settings.smsc_port, BindType.BIND_TRX,
Settings.smsc_user, Settings.smsc_password,Settings.smsc_msg_setting, TypeOfNumber.UNKNOWN,
NumberingPlanIndicator.UNKNOWN, null, Settings.smsc_timeout);
}catch(IOException ioex){
l.fatal("Connection failed due to " + ioex.getMessage());
}
ProcessSMS.s = (SMPPSession) s;
l.info("Re Connection success");
break;
}
}
}
}
Does anybody have an idea what is going on ?
Updated the JSMPP API from https://github.com/uudashr/jsmpp.
Download the source with git
run mvn install to create the jar archive.

Categories