package it.angelic.soulissclient.net; import android.os.Looper; import android.util.Log; import java.net.BindException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketTimeoutException; import java.nio.channels.ClosedByInterruptException; import java.nio.channels.DatagramChannel; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import it.angelic.soulissclient.Constants; import it.angelic.soulissclient.SoulissApp; import it.angelic.soulissclient.helpers.SoulissPreferenceHelper; /** * Apre una porta sul 23000 e si mette in ascolto per le risposte. * usa un thread pool executor, anche se active count in realta non va mai a superare uno * * @author Ale */ public class UDPRunnable implements Runnable { // implements Runnable so it can be created as a new thread private static final String TAG = "Souliss:UDP"; final int MAX_THREADS = 8; private SoulissPreferenceHelper opzioni; private DatagramSocket socket; // private Context context; private ThreadPoolExecutor threadExecutor; public UDPRunnable(SoulissPreferenceHelper opzioni) { super(); this.opzioni = opzioni; Log.d("UDP", "***UDPRunnable Created"); // this.context = ctx; threadExecutor = new ThreadPoolExecutor( MAX_THREADS / 2, // core thread pool size MAX_THREADS, // maximum thread pool size 53, // time to wait before resizing pool TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(MAX_THREADS, true), new ThreadPoolExecutor.CallerRunsPolicy()); } public void run() { // Souliss listens on port 23000 Looper.prepare(); // lifecycle //final UDPSoulissDecoder decoder = new UDPSoulissDecoder(opzioni, SoulissClient.getAppContext()); while (true) { try { // InetAddress serverAddr = InetAddress.getByName(SOULISSIP); DatagramChannel channel = DatagramChannel.open(); socket = channel.socket(); // socket = new DatagramSocket(); socket.setReuseAddress(true); socket.setBroadcast(true); // port to receive souliss board data InetSocketAddress sa = new InetSocketAddress(Constants.Net.SERVERPORT); socket.bind(sa); // create a buffer to fileCopy packet contents into byte[] buf = new byte[200]; // create a packet to receive final DatagramPacket packet = new DatagramPacket(buf, buf.length); int to = opzioni.getDataServiceIntervalMsec(); Log.d(TAG, "***Waiting on packet, timeout=" + to); socket.setSoTimeout(to); // wait to receive the packet socket.receive(packet); Log.d(TAG, "***Packet received, spawning decoder. Recvd bytes=" + packet.getLength()); // spawn a decoder and go on threadExecutor.execute(new Runnable() { @Override public void run() { UDPSoulissDecoder decoder = new UDPSoulissDecoder(opzioni, SoulissApp.getAppContext()); Log.d(TAG, "***Created decoder:" + decoder.toString()); decoder.decodeVNetDatagram(packet); } }); Log.d(TAG, "***ThreadPool, active=" + threadExecutor.getActiveCount() + ", completed:" + threadExecutor.getCompletedTaskCount() + ", poolsize:" + threadExecutor.getPoolSize()); socket.close(); } catch (BindException e) { Log.e(TAG, "***UDP Port busy, Souliss already listening? " + e.getMessage()); e.printStackTrace(); try { //Thread.sleep(opzioni.getDataServiceIntervalMsec()); socket.close(); } catch (Exception e1) { Log.e(TAG, "***UDP socket close failed: " + e1.getMessage()); } } catch (SocketTimeoutException e2) { Log.w(TAG, "***UDP SocketTimeoutException close!" + e2); socket.close(); } catch (ClosedByInterruptException xc) { xc.printStackTrace(); Log.e(TAG, "***UDP runnable interrupted!"); socket.close(); Thread.currentThread().interrupt(); return; } catch (Exception ee) { ee.printStackTrace(); Log.e(TAG, "***UDP unhandled error!" + ee.getMessage() + " of class " + ee.getClass()); socket.close(); Thread.currentThread().interrupt(); } } } }