I am banging my head on the wall. It works, but it doesn't work.
Let me clarify, testing is on a LG Optimus G, A Galaxy S4, and a Lenovo Tablet all running 4.1+
I am launching a server on each device, each device is broadcasting itself on a port, and when the user hits send, all devices that have had their service resolved, and their service has not been lost, a thread will loop launching other threads to connect to the servers broadcasting themselves, and send the data. The servers accept the incoming connection, hand it off to a thread, and then re-open themselves.
So recap, every device has is broadcasting a server, every device is supposed to know and keep track of other servers, when data is sent all known servers get hit.
My issue is that in 2/3 devices connections can consistently be established with the device's self.
Either phone, but only 1 of them at a time, seems to know about the other phone and is able to connect to the other phone. i.e. Galaxy S4 can say hi to Optimus G, but Optimus G cannot say hi except only to itself, or vice-verse.
So the discovering portion seems unreliable, and I do not know if it is me, Android, or the devices. I need outside eyes. I have tried to lay this out in a understandable and thought out manner, and I appreciate any help from any one who has knowledge on this issue as I am just making humble beginnings into the world of networks, and am more then willing to learn from someone.
I need a more reliable way of keeping track of services, or discovering them, as my implementation at least seems flawed.
I thank any help in advanced. (I do not believe this is a area that is trodden as heavily as most other android areas.)
Here is where the initialization is done.
/**initilize everything*/
private void buildNetwork()
{
Log.d(TAG, "buildNetwork");
networkHelper = new NetworkServiceDiscoveryHelper(this);
networkHelper.initializeNsd(this);
networkHelper.discoverServices();
connectionReceiver = new ConnectionReceiver(this, this);
// this next line launches the server thread which will obtain a socket
// to be used in the finishBuildingNetwork()
new Thread(connectionReceiver).start();
}
/** after the serversocket has been given a port we need to broadcast it*/
private void finishBuildingNetwork(int port)
{
Log.d(TAG, "finishBuildingNetwork");
networkHelper.registerService(port);
}
This is my somewhat changed implementation of a common NSDManager helper class.
public class NetworkServiceDiscoveryHelper
{
public static final String TAG = "NetworkServiceDiscoveryHelper";
public static final String KEY_DEVICE = "device";
Context mContext;
NsdManager mNsdManager;
NsdManager.ResolveListener mResolveListener;
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.RegistrationListener mRegistrationListener;
public static final String SERVICE_TYPE = "_http._tcp.";
public String mServiceName = "BlurbChat";
NsdServiceInfo mService;
private DiscoveredDevicesManager deviceManager;
private NetworkDiscoveryHelperListener helperListener;
/**
*
* #param context
* - the activity context the service is to be attached to
*/
public NetworkServiceDiscoveryHelper(Context context)
{
mContext = context;
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
deviceManager = new DiscoveredDevicesManager();
}
/**
* initialize the NetworkServiceDiscovery
*/
public void initializeNsd(NetworkDiscoveryHelperListener helperListener)
{
this.helperListener = helperListener;
initializeResolveListener();
initializeDiscoveryListener();
initializeRegistrationListener();
// mNsdManager.init(mContext.getMainLooper(), this);
}
private void initializeDiscoveryListener()
{
mDiscoveryListener = new NsdManager.DiscoveryListener()
{
#Override
public void onDiscoveryStarted(String regType)
{
Log.d(TAG, "Service discovery started");
helperListener.SERVICE_STARTED(regType);
}
#Override
public void onServiceFound(NsdServiceInfo service)
{
// A service was found! Do something with it.
Log.d(TAG, "Service discovery success" + service);
if (!service.getServiceType().equals(SERVICE_TYPE))
{
// Service type is the string containing the protocol and
// transport layer for this service.
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
}
else if (service.getServiceName().contains(mServiceName))
{
// we have found our service! we use .contains because if
// there are multiple device with the same service being
// broadcast they will appear with name + (index)
// Resolve a discovered service. An application can resolve
// a service right before establishing a connection to fetch
// the IP and port details on which to setup the connection.
Log.d(TAG, "Found My Service Type: " + service.getServiceType() + service.getServiceName());
helperListener.SERVICE_FOUND(service);
mNsdManager.resolveService(service, mResolveListener);
}
/***************************************************************
* Checking the service name isn't always necessary, and is only relevant if you want to connect to a specific application.
* For instance, the application might only want to connect to instances of itself running on other devices. However, if the
* application wants to connect to a network printer, it's enough to see that the service type is "_ipp._tcp".
******************************************************/
}
/**
* when we lose our service
*/
#Override
public void onServiceLost(NsdServiceInfo service)
{
// When the network service is no longer available.
Log.e(TAG, "service lost" + service);
// remove the service
if (deviceManager.removeDevice(service) != null)
{
helperListener.SERVIVCE_LOST(service);
}
}
/**
* when our service is stopped
*/
#Override
public void onDiscoveryStopped(String serviceType)
{
Log.i(TAG, "Discovery stopped: " + serviceType);
helperListener.DISCOVERY_STOPPED(serviceType);
}
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode)
{
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
helperListener.DISCOVERY_START_FAILED(serviceType, errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode)
{
helperListener.DISCOVERY_STOP_FAILED(serviceType, errorCode);
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}
private void initializeResolveListener()
{
mResolveListener = new NsdManager.ResolveListener()
{
#Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode)
{
// Called when the resolve fails. Use the error code to debug.
Log.e(TAG, "Resolve failed" + errorCode);
helperListener.RESOLVE_FAILED(serviceInfo, errorCode);
}
#Override
public void onServiceResolved(NsdServiceInfo serviceInfo)
{
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName))
{
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
DiscoveredDevice device = new DiscoveredDevice(mService.getPort(), mService.getHost(), mService.getServiceName(), mService.getServiceType());
deviceManager.addDevice(device);
helperListener.RESOLVE_SUCCESS(serviceInfo);
}
};
}
private void initializeRegistrationListener()
{
mRegistrationListener = new NsdManager.RegistrationListener()
{
#Override
public void onServiceRegistered(NsdServiceInfo serviceInfo)
{
mServiceName = serviceInfo.getServiceName();
helperListener.SERVICE_REGISTERED(serviceInfo);
}
#Override
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
{
helperListener.SERVICE_REGISTRATION_FAILED(serviceInfo, errorCode);
}
#Override
public void onServiceUnregistered(NsdServiceInfo serviceInfo)
{
helperListener.SERVICE_UNREGISTERED(serviceInfo);
}
#Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
{
helperListener.SERVICE_UNREGISTRATION_FAILED(serviceInfo, errorCode);
}
};
}
/**
* To be called after initialize()
*
* #param port
* - the port you would like to register/broadcast the service through.
*/
public void registerService(int port)
{
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setPort(port);
serviceInfo.setServiceName(mServiceName);
serviceInfo.setServiceType(SERVICE_TYPE);
mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
}
/**
* Initiate service discovery to browse for instances of a service type. Service discovery consumes network bandwidth and will continue
* until the application calls stopServiceDiscovery(NsdManager.DiscoveryListener).
*/
public void discoverServices()
{
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
/**
* Stop service discovery initiated with discoverServices(String, int, NsdManager.DiscoveryListener). An active service discovery is
* notified to the application with onDiscoveryStarted(String) and it stays active until the application invokes a stop service
* discovery. A successful stop is notified to with a call to onDiscoveryStopped(String).
*/
public void stopDiscovery()
{
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
/**
*
* #return - A class representing service information for network service discovery
*/
public NsdServiceInfo getChosenServiceInfo()
{
return mService;
}
/**
* Unregister a service registered through registerService(NsdServiceInfo, int, NsdManager.RegistrationListener). A successful
* unregister is notified to the application with a call to onServiceUnregistered(NsdServiceInfo).
*/
public void tearDown()
{
if (mNsdManager != null)
{
try
{
mNsdManager.unregisterService(mRegistrationListener);
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/**
*
* #return - the DiscoveredDevicesManager that contains all valid devices which have the appropriate service susally will call this
* after a msg of RESOLVE_SUCCESS
*/
public DiscoveredDevicesManager getDeviceManager()
{
return deviceManager;
}
}
and finally this is the basis of the server
#Override
public void run()
{
try
{
receiverSocket = new ServerSocket(0);
onPortObtained(receiverSocket.getLocalPort());
Log.d(TAG, "run");
while (broadcastConnection)
{
try
{
Socket newConnectionSocket = receiverSocket.accept();
onNewConnection(newConnectionSocket.getRemoteSocketAddress(), newConnectionSocket.getLocalSocketAddress());
// to clarify this line launches a function that starts threads to handle the socket.
recieveConnection(newConnectionSocket);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
Edit: one more thing, sometimes while running the devices will randomly restart. No common thing causing, other then they are running the app.
With the service discovery being just to difficult to handle, I will build my own discovery by doing a initial ping like so
List<DiscoveredDevice> devices = new ArrayList<DiscoveredDevice>();
for (int i = 0; i < 256; i++)
{
// this hardcoded ip will be variable from the wifi's ip
String ip = "xx.xx.x." + i;
// this socket may be forever hard coded unless i find a better way. :(
devices.add(new DiscoveredDevice(32999, ip, "", ""));
}
hitting all devices, registering every device that accepts, and every device that accepts registering it.
On leave it will dispatch a command to be removed from every devices queue, and upon trying to send a device a connection that does not get accepted it will be removed.
Hackish, but the Android way wasn't working for me :(, and this way works beautifully.
Related
I have an Android app that runs a motor controller via ethernet and connects to some servers for API operations over wifi. Using Android Studio's simulator I can use both wifi and ethernet at the same time and everything works fine. However, when I use my actual android tablet it only allows me to use ethernet OR wifi.
The android tablet is running android 7.1.2. I have the setting "Wifi Ethernet Share" toggled ON in network settings on the tablet which appears to allow wifi to be connected to the internet when the device is also connected to ethernet. With this setting OFF, the app prioritizes ethernet and I cannot use Wifi for API operations.
Here is my class which handles Modbus operations (reading from the motor controller over ethernet):
public class ModbusRead {
private static final String TAG = "MODBUS READ";
ModbusClient mClientReadAll;
public ModbusRead()
{
// IP = "192.168.124.2";
// port = 502;
mClientReadAll = new ModbusClient(Modbus.IP, Integer.valueOf(Modbus.port));
mClientReadAll.setUnitIdentifier((byte)255);
}
public Runnable readAll()
{
return () -> {
ReadAllFromModbus mReadAll = new ReadAllFromModbus();
mReadAll.execute();
};
}
public class ReadAllFromModbus extends AsyncTask<String, Void, String> {
private final String TAG = "READ ALL FROM MODBUS";
#Override
protected String doInBackground(String... params) {
try
{
mClientReadAll.Connect();
// get all registers
int[] registerBlock = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_MODE.getRegister()- 1, 16);
int[] wideRegisters = new int[] {
Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_POSITION.getRegister() - 1, 2)),
Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_TARGET_POSITION.getRegister() - 1, 2)),
Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ROM_DELTA.getRegister() - 1, 2)),
Modbus.convertWideRegister(mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_REWIND_ZERO.getRegister() - 1, 2))
};
int[] tensionRegister = mClientReadAll.ReadHoldingRegisters(Constants.RegisterRead.HR_ACTUAL_TENSION.getRegister() - 1, 1);
Modbus.updateAllRegisters(registerBlock, wideRegisters, tensionRegister);
}
catch (Exception e)
{
Log.i(TAG, "ERROR IN GETTING ALL REGISTERS LOOP: " + e.getMessage());
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.i(TAG, "CURRENT MODE: " + State.OP_MODE);
try
{
mClientReadAll.Disconnect();
}
catch(Exception e)
{
Log.i(TAG, "ERROR IN DISCONNECTING");
}
}
}
}
Here is the relevant code from my MainActivity.java class that is the launch activity of my app:
final ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkRequest requestEthernet = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.build();
final ConnectivityManager.NetworkCallback cbEthernet = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
// connectivityManager.bindProcessToNetwork(network);
try
{
// Modbus.IP = "192.168.124.2"
// Modbus.port = 502
Log.i(TAG, "TRYING TO BIND SOCKET...");
Socket socket = new Socket(Modbus.IP, Modbus.port);
Log.i(TAG, "SOCKET CREATED..." + socket.getInetAddress());
network.bindSocket(socket);
Log.i(TAG, "BOUND ETHERNET");
ModbusRead modbusRead = new ModbusRead();
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(modbusRead.readAll(), 2000, 250, TimeUnit.MILLISECONDS);
}
catch (Exception e)
{
e.printStackTrace();
Log.i(TAG, "EXCEPTION: " + e.getMessage());
}
}
};
connectivityManager.requestNetwork(requestEthernet, cbEthernet);
I was pointed to this type of solution by user #AlwaysLearning who helped me get this far in a different post. My problem now is that when I try and create the socket, it hangs until eventually throwing a "Connection Timed Out" exception. If I use the commented-out command of connectivityManager.bindProcessToNetwork(network); instead of the socket-creation code block it does connect to the motor controller no problem, but then I cannot use wifi for API operations as the whole system is directing network traffic through ethernet.
Does anyone know how to proceed from here? I only have some experience in Java, none in networking, and am brand new to Android itself so any help at all is appreciated!
I have a question regarding JAVA-MULTITHREADING.
I have a jetty webapp with an grpc-streaming-client. everything is fine but how can I built up a model for getting the streaming data?
The webapp is build up with jsf. in that i have a controller which invokes a handler class for starting the stream:
public void startStream(){
if(streamHandler!=null & activatedStream == false){
streamHandler.startStreamClient();
activatedStream = true;
}else{
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Could not initialize the StreamHandler and Client Class or a Stream still runs. Please check the logs.", "Stream is running: "+String.valueOf(activatedStream));
FacesContext.getCurrentInstance().addMessage(null, message);
}
}
This method simple starts the client and the stream.
public void startStreamClient(){
log.info("Calling startMethod of Handler............");
CountDownLatch finishLatch;
if(this.client.isChannelShutdown()& this.client!=null){
this.client=new StreamClient(this.serverHost, this.serverPort);
try{
finishLatch = this.client.imageStream(this.startRequest);
}catch(Exception e){
log.warn("Error while starting the imageStream: "+e.getLocalizedMessage(), e);
}
}else{
finishLatch = client.imageStream(this.startRequest);
}
}
The Implementation of checking CountDownLatch is still missing. But it does not matter in this case.
The Responses comes here: The onNext()-Method is giving the streamed Data:
public CountDownLatch imageStream(StreamRequest request){
log.info("Calling imageStream-asnychStub...............");
CountDownLatch finish = new CountDownLatch(1);
/**
* The asyncStub is calling the rpc-Function with a new StreamObserver for the given Responses from the Server.
*/
StreamObserver<StreamRequest> requestOberserver = asyncStub.streamImagaData(new StreamObserver<StreamResponse>() {
/**
* The onNext Method is getting the imageDate, if it is send
*/
#Override
public void onNext(StreamResponse response) {
System.out.println("Data-Input: "+response.getImageData().length());
}
/**
* The onError Method is getting an Exception Object if it is thrown
*/
#Override
public void onError(Throwable t) {
log.warn("Bidirectional Stream with Server an Client: "+t.getLocalizedMessage(), t);
}
/**
* The onCompleted is for ending the Stream and reduces the CountDownLatch by one
*/
#Override
public void onCompleted() {
log.info("Bidirectional Streaming has finished....");
finish.countDown();
}
});
/**
* This Block is for sending a StreamRequest to the Server.
*/
try{
log.info("Sending a Streaming-Request to Server with State: "+request.getStreamState().name());
requestOberserver.onNext(request);
}catch (RuntimeException ex) {
log.warn("Error sending requst to Server: "+ex.getLocalizedMessage(), ex);
requestOberserver.onError(ex);
}
requestOberserver.onCompleted();
return finish;
}
The Imagedata is simple printed on Screen. I tried to build up a consumer-producer-model but failed because the response returns in an innertyp of StreamObserver.
How can I get this Data in realtime. Do I have to create an official implementation of the StreamObserver? Or where do I have to place the additional Threads? Are Threads the only choice? Do i need some callables?
Thanks in advance.
I have solved the problem by implmenting the observer-pattern.
The ManagedBean becam the Observer of the StreamClient.
I have tried to call no of web services in a sequential manner like one by one as below. Once all web services run successfully task is over. If not then there must be showing the alert to the user.
Code:
Dialog progressDialog = ComponentUtils.getFormattedDialog(new Dialog());
progressDialog.showModeless();
boolean allDone = true;
for(int i=0;i<serviceList.size();i++){
String serviceUrl = serviceList.get(i);
boolean service = getServiceResponse(serviceUrl);
if(service==false){
progressDialog.dispose();
allDone = false;
break;
}
}
if(allDone){
progressDialog.dispose();
Dialog.show("SUCCESS","Process Done","OK",null);
}
else{
Dialog.show("FAIL","Process Failed","OK",null)
}
...
public static boolean getServiceResponse(String serviceUrl){
boolean isSuccess = false;
ConnectionRequest connectionRequest = new ConnectionRequest() {
#Override
protected void handleErrorResponseCode(int code, String message) {
this.kill();
LogUtil.setErrorLog(message,page_name+ " > handleErrorResponseCode");
isSuccess = false
}
#Override
protected void handleException(Exception err) {
this.kill();
LogUtil.setErrorLog(err,page_name + " > handleException");
isSuccess = false
}
#Override
protected void readResponse(InputStream input) {
isSuccess = true
}
};
connectionRequest.setUrl(serviceUrl);
connectionRequest.setContentType("application/x-www-form-urlencoded");
connectionRequest.setPost(true);
connectionRequest.setDuplicateSupported(true);
connectionRequest.setTimeout(100000);
NetworkManager.getInstance().addToQueueAndWait(connectionRequest);
return isSuccess;
}
Whenever I am trying to sync process in the full network it works fine as aspected.
But during the process, if network runs slow or lost then it will not tend to alert the user to the issue. instead, it just sticks on process dialog.
I have added error log in one file to check later on for the issue. But that also not showing any error in this case.
Any help will be more appreciable.
Timeout in Codename One is currently limited to connection timeout and doesn't apply to read timeout so once a connection is made it will last. You can use a progress listener on the NetworkManager to detect such situations and kill the connection.
I am trying to set up GCM but my project doesn't recognize certain methods. I followed the advice of many other links which was to import GCM and google play services but I am still getting no such luck. Thanks for looking.
Edit: I've cleaned a million times and rebuilt.
I'm not sure where you got the code of the demo app from, but there are several things wrong with it.
First of all, the method you are missing is not implemented in the Demo. It has an empty body :
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP or CCS to send
* messages to your app. Not needed for this demo since the device sends upstream messages
* to a server that echoes back the message using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
It's your responsibility to implement it, since its implementation depends on your server implementation.
Another error (you'd get an exception after you fix the compilation error) is calling gcm.register() from the main thread. You must call it in the background :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mDisplay = (TextView) findViewById(R.id.display);
context = getApplicationContext();
// Check device for Play Services APK. If check succeeds, proceed with GCM registration.
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty()) {
registerInBackground();
}
} else {
Log.i(TAG, "No valid Google Play Services APK found.");
}
}
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and the app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP, so it
// can use GCM/HTTP or CCS to send messages to your app.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device will send
// upstream messages to a server that echo back the message using the
// 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
All code samples are taken from the official GCM Demo app.
I'm using websockets to make a multiplayer game and I need to send multiple types of data across the server but when I connect to the server it's supposed to send back a name and number ("type") and ("data") respectively from the websocket library on connection. I don't need the type but ("data") is vital for the game logic to actually work.
Below is the code I have in my websockets onMessage() function:
#Override
public void onMessage(String message)
{
try
{
JSONObject json = new JSONObject(message);
if(json.has("type") && json.has("data"))
{
Log.d(TAG, json.getString("type"));
Log.d(TAG, json.getString("data"));
playerNum = Integer.parseInt(json.getString("data"));
Log.d(TAG,"Received... Type : " +json.getString("type")+" Data : "+json.getString("data"));
}
if(json.has("Player1TurnOver"))
{
player1TurnOver = json.getBoolean("Player1TurnOver");
}
if(json.has("Word"))
{
String b = json.getString("Word");
bWord = new char[b.length()];
for(int i = 0; i < b.length(); i++)
{
bWord[i] = b.charAt(i);
}
wordLength = bWord.length;
}
}
catch(JSONException e)
{
}
}
But this is never called from the server even though the client has a listener as such:
mClient = new WebSocketClient(URI.create("ws://some_ip:8080/wstest"), new WebSocketClient.Listener()){
And the listener is initialised within the websocket library class
public interface Listener {
public void onConnect();
public void onMessage(String message);
public void onMessage(byte[] data);
public void onDisconnect(int code, String reason);
public void onError(Exception error);
}
I can't seem to figure out why this isn't working properly. As it has worked before...
Sometimes it is not correctly detected when a device looses internet connection (Java is not that smart in this case ;) )
Apart from this. Could you maybe activate the debug printouts with WebSocketImpl.DEBUG = true;
The lib will automatically send pings to the endpoints at specific interval and if no ping was received it assumes that the endpoint got disconnected!