Added error handling and comments to ServiceDiscoveryThread. Assorted logging.

This commit is contained in:
2013-11-27 08:10:48 -04:30
parent c1916a667e
commit 44b58565ff
5 changed files with 80 additions and 20 deletions

View File

@@ -102,11 +102,11 @@ public class Main implements ApplicationListener, NetworkConnectionListener {
} }
@Override @Override
public synchronized void interfaceConnected(String iface) { public synchronized void networkStreamConnected(String streamName) {
if(iface.compareTo(VideoStreamingThread.THREAD_NAME) == 0 || iface.compareTo(RobotControlThread.THREAD_NAME) == 0) if(streamName.compareTo(VideoStreamingThread.THREAD_NAME) == 0 || streamName.compareTo(RobotControlThread.THREAD_NAME) == 0)
connections += 1; connections += 1;
if(connections >= 2){ if(connections >= 2){
Gdx.app.debug(TAG, CLASS_NAME + ".interfaceConnected() :: Stopping service broadcast."); Gdx.app.debug(TAG, CLASS_NAME + ".networkStreamConnected() :: Stopping service broadcast.");
udpThread.finish(); udpThread.finish();
mcastEnabler.disableMulticast(); mcastEnabler.disableMulticast();
} }

View File

@@ -1,5 +1,5 @@
package ve.ucv.ciens.ccg.nxtar.interfaces; package ve.ucv.ciens.ccg.nxtar.interfaces;
public interface NetworkConnectionListener { public interface NetworkConnectionListener {
public void interfaceConnected(String iface); public void networkStreamConnected(String streamName);
} }

View File

@@ -42,7 +42,7 @@ public class RobotControlThread extends Thread {
try{ try{
client = server.accept(); client = server.accept();
if(netListener != null) if(netListener != null)
netListener.interfaceConnected(THREAD_NAME); netListener.networkStreamConnected(THREAD_NAME);
toaster.showShortToast("Client connected to RobotControlThread"); toaster.showShortToast("Client connected to RobotControlThread");
client.close(); client.close();
}catch(IOException io){ }catch(IOException io){

View File

@@ -10,10 +10,36 @@ import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
/**
* Ad hoc service discovery server thread.
*
* <p> This thread performs an ad hoc service discovery protocol. A multicast datagram packet is sent every
* 250 miliseconds carrying the string "NxtAR server is here!" on the multicast address defined
* in {@link ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants#MULTICAST_ADDRESS}. The port defined in
* {@link ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants#SERVER_UDP_PORT} is used for the transmissions. The server stops
* when another thread calls the {@link #finish()} method or the server fails to transmit {@link #MAX_RETRIES} packets in
* a row, whichever happens first.</p>
*
* @author miky
* @since 27/11/2013
*/
public class ServiceDiscoveryThread extends Thread { public class ServiceDiscoveryThread extends Thread {
/**
* The name used to identify this thread.
*/
public static final String THREAD_NAME = "ServiceDiscoveryThread"; public static final String THREAD_NAME = "ServiceDiscoveryThread";
/**
* Tag used for logging.
*/
private static final String TAG = "NXTAR_CORE_UDPTHREAD"; private static final String TAG = "NXTAR_CORE_UDPTHREAD";
/**
* Class name used for logging.
*/
private static final String CLASS_NAME = ServiceDiscoveryThread.class.getSimpleName(); private static final String CLASS_NAME = ServiceDiscoveryThread.class.getSimpleName();
/**
* Maximum number of transmission attempts before ending the thread abruptly.
*/
private static final int MAX_RETRIES = 5;
private Object semaphore; private Object semaphore;
private boolean done; private boolean done;
@@ -21,48 +47,82 @@ public class ServiceDiscoveryThread extends Thread {
private InetAddress group; private InetAddress group;
public ServiceDiscoveryThread(){ public ServiceDiscoveryThread(){
// Setup this thread name.
super(THREAD_NAME); super(THREAD_NAME);
done = false; done = false;
semaphore = new Object(); semaphore = new Object();
// Try to get the InetAddress defined by the IP address defined in ProjectConstants.MULTICAST_ADDRESS.
try{ try{
group = InetAddress.getByName(ProjectConstants.MULTICAST_ADDRESS); group = InetAddress.getByName(ProjectConstants.MULTICAST_ADDRESS);
}catch(UnknownHostException uh){ } }catch(UnknownHostException uh){
group = null;
}
// Create a UDP socket at the port defined in ProjectConstants.SERVER_UDP_PORT.
Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Creating multicast server."); Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Creating multicast server.");
try{ try{
udpServer = new DatagramSocket(ProjectConstants.SERVER_UDP_PORT); udpServer = new DatagramSocket(ProjectConstants.SERVER_UDP_PORT);
}catch(IOException io){ }catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Error creating UDP socket: " + io.getMessage(), io); Gdx.app.error(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Error creating UDP socket: " + io.getMessage());
udpServer = null;
} }
Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Multicast server created."); Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Multicast server created.");
} }
@Override @Override
public void run(){ public void run(){
int retries = 0;
byte[] buffer = (new String("NxtAR server here!")).getBytes(); byte[] buffer = (new String("NxtAR server here!")).getBytes();
try{
while(true){ // If failed to get any of the required network elements then end the thread right away.
synchronized(semaphore){ if(group == null || udpServer == null){
if(done){ Gdx.app.error(TAG, CLASS_NAME + ".run() :: No multicast address defined, ending thread.");
udpServer.close(); return;
break; }
} if(group == null){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: No server available, ending thread.");
return;
}
while(true){
// Verify if the thread should end. If that is the case, close the server.
synchronized(semaphore){
if(done){
udpServer.close();
break;
} }
//Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Resending packet"); }
try{
// End the thread if already at the last retry attempt after too many failed transmissions.
if(retries >= MAX_RETRIES){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Too many failed transmissions, ending thread.");
udpServer.close();
break;
}
// Send the packet and reset the retry counter.
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, ProjectConstants.SERVER_UDP_PORT); DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, ProjectConstants.SERVER_UDP_PORT);
udpServer.send(packet); udpServer.send(packet);
//Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Packet sent"); retries = 0;
try{ sleep(250L); }catch(InterruptedException ie){ } try{ sleep(250L); }catch(InterruptedException ie){ }
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Error sending packet: " + io.getMessage());
retries += 1;
} }
}catch(IOException io){
Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Error sending packet: " + io.getMessage(), io);
} }
if(retries < MAX_RETRIES)
Gdx.app.debug(TAG, CLASS_NAME + ".run() :: Service discovery successfully terminated.");
else
Gdx.app.debug(TAG, CLASS_NAME + ".run() :: Service discovery terminated after too many failed transmissions.");
} }
/**
* Marks this thread as ready to end.
*/
public void finish(){ public void finish(){
synchronized(semaphore){ synchronized(semaphore){
Gdx.app.debug(TAG, CLASS_NAME + ".finish() :: Finishing service discovery thread.");
done = true; done = true;
} }
} }

View File

@@ -42,7 +42,7 @@ public class VideoStreamingThread extends Thread {
try{ try{
client = server.accept(); client = server.accept();
if(netListener != null) if(netListener != null)
netListener.interfaceConnected(THREAD_NAME); netListener.networkStreamConnected(THREAD_NAME);
toaster.showShortToast("Client connected to VideoStreamingThread"); toaster.showShortToast("Client connected to VideoStreamingThread");
client.close(); client.close();
}catch(IOException io){ }catch(IOException io){