From c6ab7a9edb18fe237c5a7a7116f6a79a6d6c2d5a Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Thu, 7 May 2020 14:07:56 +0200 Subject: [PATCH 1/3] Fix threads --- .../react/tcpsocket/TcpReceiverTask.java | 2 +- .../react/tcpsocket/TcpSocketClient.java | 18 ++++++++++++------ .../react/tcpsocket/TcpSocketModule.java | 17 ++++++++++------- .../react/tcpsocket/TcpSocketServer.java | 9 +++++---- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpReceiverTask.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpReceiverTask.java index 6b9b782..fdee11f 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpReceiverTask.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpReceiverTask.java @@ -14,7 +14,7 @@ * notifies it's listener when data is received. This is not threadsafe, the listener * should handle synchronicity. */ -public class TcpReceiverTask extends AsyncTask, Void, Void> { +class TcpReceiverTask extends AsyncTask, Void, Void> { /** * An infinite loop to block and read data from the socket. */ diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java index ce259e4..2c95417 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java @@ -2,7 +2,6 @@ import android.content.Context; import android.net.Network; -import android.os.AsyncTask; import android.util.Pair; import com.facebook.react.bridge.ReadableMap; @@ -13,6 +12,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.security.GeneralSecurityException; +import java.util.concurrent.ExecutorService; import javax.net.SocketFactory; import javax.net.ssl.SSLSocket; @@ -23,16 +23,18 @@ class TcpSocketClient { private final int id; + private final ExecutorService executorService; private TcpReceiverTask receiverTask; private Socket socket; private TcpReceiverTask.OnDataReceivedListener mReceiverListener; - TcpSocketClient(final int id) { + TcpSocketClient(final int id, final ExecutorService executorService) { this.id = id; + this.executorService = executorService; } - TcpSocketClient(@NonNull final TcpReceiverTask.OnDataReceivedListener receiverListener, @NonNull final Integer id, @Nullable final Socket socket) { - this(id); + TcpSocketClient(@NonNull final TcpReceiverTask.OnDataReceivedListener receiverListener, @NonNull final Integer id, @NonNull final ExecutorService executorService, @Nullable final Socket socket) { + this(id, executorService); this.socket = socket; receiverTask = new TcpReceiverTask(); mReceiverListener = receiverListener; @@ -52,7 +54,7 @@ public void connect(@NonNull final Context context, @NonNull final String addres final boolean isTls = options.hasKey("tls") && options.getBoolean("tls"); if (isTls) { SocketFactory sf; - if (options.hasKey("tlsCheckValidity") && !options.getBoolean("tlsCheckValidity")){ + if (options.hasKey("tlsCheckValidity") && !options.getBoolean("tlsCheckValidity")) { sf = SSLCertificateHelper.createBlindSocketFactory(); } else { final String customTlsCert = options.hasKey("tlsCert") ? options.getString("tlsCert") : null; @@ -86,10 +88,14 @@ public void connect(@NonNull final Context context, @NonNull final String addres startListening(); } + ExecutorService getExecutorService() { + return this.executorService; + } + @SuppressWarnings("WeakerAccess") public void startListening() { //noinspection unchecked - receiverTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Pair<>(this, mReceiverListener)); + receiverTask.executeOnExecutor(getExecutorService(), new Pair<>(this, mReceiverListener)); } /** diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java index abbccca..6c4110e 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java @@ -6,7 +6,6 @@ import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.os.AsyncTask; import android.util.Base64; import android.net.Network; @@ -26,6 +25,8 @@ import java.net.InetSocketAddress; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -34,10 +35,12 @@ public class TcpSocketModule extends ReactContextBaseJavaModule implements TcpReceiverTask.OnDataReceivedListener { private static final String TAG = "TcpSockets"; + private static final int N_THREADS = 2; private final ReactApplicationContext mReactContext; private final ConcurrentHashMap socketClients = new ConcurrentHashMap<>(); private final ConcurrentHashMap mNetworkMap = new ConcurrentHashMap<>(); private final CurrentNetwork currentNetwork = new CurrentNetwork(); + private final ExecutorService executorService = Executors.newFixedThreadPool(N_THREADS); public TcpSocketModule(ReactApplicationContext reactContext) { super(reactContext); @@ -81,7 +84,7 @@ protected void doInBackgroundGuarded(Void... params) { final String localAddress = options.hasKey("localAddress") ? options.getString("localAddress") : null; final String iface = options.hasKey("interface") ? options.getString("interface") : null; selectNetwork(iface, localAddress); - client = new TcpSocketClient(TcpSocketModule.this, cId, null); + client = new TcpSocketClient(TcpSocketModule.this, cId, executorService, null); socketClients.put(cId, client); client.connect(mReactContext, host, port, options, currentNetwork.getNetwork()); onConnect(cId, host, port); @@ -89,7 +92,7 @@ protected void doInBackgroundGuarded(Void... params) { onError(cId, e.getMessage()); } } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }.executeOnExecutor(executorService); } @SuppressLint("StaticFieldLeak") @@ -115,7 +118,7 @@ protected void doInBackgroundGuarded(Void... params) { onError(cId, e.toString()); } } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }.executeOnExecutor(executorService); } @SuppressLint("StaticFieldLeak") @@ -132,7 +135,7 @@ protected void doInBackgroundGuarded(Void... params) { socketClient.close(); socketClients.remove(cId); } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }.executeOnExecutor(executorService); } @SuppressWarnings("unused") @@ -149,7 +152,7 @@ public void listen(final Integer cId, final ReadableMap options) { @Override protected void doInBackgroundGuarded(Void... params) { try { - TcpSocketServer server = new TcpSocketServer(socketClients, TcpSocketModule.this, cId, options); + TcpSocketServer server = new TcpSocketServer(socketClients, TcpSocketModule.this, cId, executorService, options); socketClients.put(cId, server); int port = options.getInt("port"); String host = options.getString("host"); @@ -158,7 +161,7 @@ protected void doInBackgroundGuarded(Void... params) { onError(cId, uhe.getMessage()); } } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }.executeOnExecutor(executorService); } private void requestNetwork(final int transportType) throws InterruptedException { diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java index 9d3f78b..8956bd7 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java @@ -11,6 +11,7 @@ import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; public final class TcpSocketServer extends TcpSocketClient { private ServerSocket serverSocket; @@ -26,7 +27,7 @@ protected Void doInBackground(Object[] objects) { while (!isCancelled() && !serverSocket.isClosed()) { Socket socket = serverSocket.accept(); int clientId = getClientId(); - TcpSocketClient socketClient = new TcpSocketClient(mReceiverListener, clientId, socket); + TcpSocketClient socketClient = new TcpSocketClient(mReceiverListener, clientId, getExecutorService(), socket); socketClients.put(clientId, socketClient); socketClient.startListening(); mReceiverListener.onConnection(getId(), clientId, new InetSocketAddress(socket.getInetAddress(), socket.getPort())); @@ -41,9 +42,9 @@ protected Void doInBackground(Object[] objects) { }; - public TcpSocketServer(final ConcurrentHashMap socketClients, final TcpReceiverTask.OnDataReceivedListener receiverListener, final Integer id, + public TcpSocketServer(final ConcurrentHashMap socketClients, final TcpReceiverTask.OnDataReceivedListener receiverListener, final Integer id, final ExecutorService executorService, final ReadableMap options) throws IOException { - super(id); + super(id, executorService); // Get data from options int port = options.getInt("port"); String address = options.getString("host"); @@ -76,7 +77,7 @@ private int getClientId() { private void listen() { //noinspection unchecked - listening.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + listening.executeOnExecutor(getExecutorService()); } @Override From 7651928fa5fb552658de4c8a28962ad22e6692f2 Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Thu, 7 May 2020 15:11:43 +0200 Subject: [PATCH 2/3] Each socket has it's own executor now --- .../react/tcpsocket/TcpSocketClient.java | 19 ++++++++++--------- .../react/tcpsocket/TcpSocketModule.java | 2 +- .../react/tcpsocket/TcpSocketServer.java | 7 ++++--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java index 2c95417..5474bdb 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java @@ -6,13 +6,14 @@ import com.facebook.react.bridge.ReadableMap; -import java.io.OutputStream; import java.io.IOException; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.security.GeneralSecurityException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import javax.net.SocketFactory; import javax.net.ssl.SSLSocket; @@ -28,18 +29,21 @@ class TcpSocketClient { private Socket socket; private TcpReceiverTask.OnDataReceivedListener mReceiverListener; - TcpSocketClient(final int id, final ExecutorService executorService) { + TcpSocketClient(final int id) { this.id = id; - this.executorService = executorService; + this.executorService = Executors.newFixedThreadPool(1); } - TcpSocketClient(@NonNull final TcpReceiverTask.OnDataReceivedListener receiverListener, @NonNull final Integer id, @NonNull final ExecutorService executorService, @Nullable final Socket socket) { - this(id, executorService); + TcpSocketClient(@NonNull final TcpReceiverTask.OnDataReceivedListener receiverListener, @NonNull final Integer id, @Nullable final Socket socket) { + this(id); this.socket = socket; receiverTask = new TcpReceiverTask(); mReceiverListener = receiverListener; } + ExecutorService getExecutorService() { + return this.executorService; + } public int getId() { return id; @@ -88,10 +92,6 @@ public void connect(@NonNull final Context context, @NonNull final String addres startListening(); } - ExecutorService getExecutorService() { - return this.executorService; - } - @SuppressWarnings("WeakerAccess") public void startListening() { //noinspection unchecked @@ -119,6 +119,7 @@ public void close() { if (receiverTask != null && !receiverTask.isCancelled()) { // stop the receiving task receiverTask.cancel(true); + getExecutorService().shutdown(); } // close the socket if (socket != null && !socket.isClosed()) { diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java index 6c4110e..d7276ed 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java @@ -84,7 +84,7 @@ protected void doInBackgroundGuarded(Void... params) { final String localAddress = options.hasKey("localAddress") ? options.getString("localAddress") : null; final String iface = options.hasKey("interface") ? options.getString("interface") : null; selectNetwork(iface, localAddress); - client = new TcpSocketClient(TcpSocketModule.this, cId, executorService, null); + client = new TcpSocketClient(TcpSocketModule.this, cId, null); socketClients.put(cId, client); client.connect(mReactContext, host, port, options, currentNetwork.getNetwork()); onConnect(cId, host, port); diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java index 8956bd7..43d970a 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketServer.java @@ -27,7 +27,7 @@ protected Void doInBackground(Object[] objects) { while (!isCancelled() && !serverSocket.isClosed()) { Socket socket = serverSocket.accept(); int clientId = getClientId(); - TcpSocketClient socketClient = new TcpSocketClient(mReceiverListener, clientId, getExecutorService(), socket); + TcpSocketClient socketClient = new TcpSocketClient(mReceiverListener, clientId, socket); socketClients.put(clientId, socketClient); socketClient.startListening(); mReceiverListener.onConnection(getId(), clientId, new InetSocketAddress(socket.getInetAddress(), socket.getPort())); @@ -42,9 +42,9 @@ protected Void doInBackground(Object[] objects) { }; - public TcpSocketServer(final ConcurrentHashMap socketClients, final TcpReceiverTask.OnDataReceivedListener receiverListener, final Integer id, final ExecutorService executorService, + public TcpSocketServer(final ConcurrentHashMap socketClients, final TcpReceiverTask.OnDataReceivedListener receiverListener, final Integer id, final ReadableMap options) throws IOException { - super(id, executorService); + super(id); // Get data from options int port = options.getInt("port"); String address = options.getString("host"); @@ -91,6 +91,7 @@ public void close() { if (!listening.isCancelled()) { // stop the receiving task listening.cancel(true); + getExecutorService().shutdown(); } // close the socket From 310d14702af98a195cd95aedc20979604b01124b Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Thu, 7 May 2020 15:14:53 +0200 Subject: [PATCH 3/3] Update fixes --- .../java/com/asterinet/react/tcpsocket/TcpSocketModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java index d7276ed..b6f6fae 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java @@ -152,7 +152,7 @@ public void listen(final Integer cId, final ReadableMap options) { @Override protected void doInBackgroundGuarded(Void... params) { try { - TcpSocketServer server = new TcpSocketServer(socketClients, TcpSocketModule.this, cId, executorService, options); + TcpSocketServer server = new TcpSocketServer(socketClients, TcpSocketModule.this, cId, options); socketClients.put(cId, server); int port = options.getInt("port"); String host = options.getString("host");