From 05a2819a58fac3c7da474bdc6c35105e95e925a4 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 16:40:47 +0100 Subject: [PATCH 01/14] Net-client: use final field for lock --- .../libraries/net/src/processing/net/Client.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index 11287c59e..04b3de1ad 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -57,6 +57,8 @@ public class Client implements Runnable { public InputStream input; public OutputStream output; + final Object bufferLock = new Object[0]; + byte buffer[] = new byte[32768]; int bufferIndex; int bufferLast; @@ -230,7 +232,7 @@ public class Client implements Runnable { return; } - synchronized (buffer) { + synchronized (bufferLock) { // todo: at some point buffer should stop increasing in size, // otherwise it could use up all the memory. if (bufferLast == buffer.length) { @@ -341,7 +343,7 @@ public class Client implements Runnable { public int read() { if (bufferIndex == bufferLast) return -1; - synchronized (buffer) { + synchronized (bufferLock) { int outgoing = buffer[bufferIndex++] & 0xff; if (bufferIndex == bufferLast) { // rewind bufferIndex = 0; @@ -394,7 +396,7 @@ public class Client implements Runnable { public byte[] readBytes() { if (bufferIndex == bufferLast) return null; - synchronized (buffer) { + synchronized (bufferLock) { int length = bufferLast - bufferIndex; byte outgoing[] = new byte[length]; System.arraycopy(buffer, bufferIndex, outgoing, 0, length); @@ -419,7 +421,7 @@ public class Client implements Runnable { public byte[] readBytes(int max) { if (bufferIndex == bufferLast) return null; - synchronized (buffer) { + synchronized (bufferLock) { int length = bufferLast - bufferIndex; if (length > max) length = max; byte outgoing[] = new byte[length]; @@ -451,7 +453,7 @@ public class Client implements Runnable { public int readBytes(byte bytebuffer[]) { if (bufferIndex == bufferLast) return 0; - synchronized (buffer) { + synchronized (bufferLock) { int length = bufferLast - bufferIndex; if (length > bytebuffer.length) length = bytebuffer.length; System.arraycopy(buffer, bufferIndex, bytebuffer, 0, length); @@ -490,7 +492,7 @@ public class Client implements Runnable { if (bufferIndex == bufferLast) return null; byte what = (byte)interesting; - synchronized (buffer) { + synchronized (bufferLock) { int found = -1; for (int k = bufferIndex; k < bufferLast; k++) { if (buffer[k] == what) { @@ -531,7 +533,7 @@ public class Client implements Runnable { if (bufferIndex == bufferLast) return 0; byte what = (byte)interesting; - synchronized (buffer) { + synchronized (bufferLock) { int found = -1; for (int k = bufferIndex; k < bufferLast; k++) { if (buffer[k] == what) { From f140299e48481f54ca4eec0ab7b0fde7295fa610 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 16:42:45 +0100 Subject: [PATCH 02/14] Net-client: synchronize access to all concurrently modified fields --- .../net/src/processing/net/Client.java | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index 04b3de1ad..4eda3b824 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -49,7 +49,7 @@ public class Client implements Runnable { Method clientEventMethod; Method disconnectEventMethod; - Thread thread; + volatile Thread thread; Socket socket; int port; String host; @@ -308,7 +308,9 @@ public class Client implements Runnable { * @brief Returns the number of bytes in the buffer waiting to be read */ public int available() { - return (bufferLast - bufferIndex); + synchronized (bufferLock) { + return (bufferLast - bufferIndex); + } } @@ -323,8 +325,10 @@ public class Client implements Runnable { * @brief Clears the buffer */ public void clear() { - bufferLast = 0; - bufferIndex = 0; + synchronized (bufferLock) { + bufferLast = 0; + bufferIndex = 0; + } } @@ -341,9 +345,9 @@ public class Client implements Runnable { * @brief Returns a value from the buffer */ public int read() { - if (bufferIndex == bufferLast) return -1; - synchronized (bufferLock) { + if (bufferIndex == bufferLast) return -1; + int outgoing = buffer[bufferIndex++] & 0xff; if (bufferIndex == bufferLast) { // rewind bufferIndex = 0; @@ -366,8 +370,10 @@ public class Client implements Runnable { * @brief Returns the next byte in the buffer as a char */ public char readChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) read(); + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return (char) (-1); + return (char) read(); + } } @@ -394,9 +400,9 @@ public class Client implements Runnable { * @brief Reads everything in the buffer */ public byte[] readBytes() { - if (bufferIndex == bufferLast) return null; - synchronized (bufferLock) { + if (bufferIndex == bufferLast) return null; + int length = bufferLast - bufferIndex; byte outgoing[] = new byte[length]; System.arraycopy(buffer, bufferIndex, outgoing, 0, length); @@ -419,9 +425,9 @@ public class Client implements Runnable { * @param max the maximum number of bytes to read */ public byte[] readBytes(int max) { - if (bufferIndex == bufferLast) return null; - synchronized (bufferLock) { + if (bufferIndex == bufferLast) return null; + int length = bufferLast - bufferIndex; if (length > max) length = max; byte outgoing[] = new byte[length]; @@ -451,9 +457,9 @@ public class Client implements Runnable { * @param bytebuffer passed in byte array to be altered */ public int readBytes(byte bytebuffer[]) { - if (bufferIndex == bufferLast) return 0; - synchronized (bufferLock) { + if (bufferIndex == bufferLast) return 0; + int length = bufferLast - bufferIndex; if (length > bytebuffer.length) length = bytebuffer.length; System.arraycopy(buffer, bufferIndex, bytebuffer, 0, length); @@ -489,10 +495,11 @@ public class Client implements Runnable { * @param interesting character designated to mark the end of the data */ public byte[] readBytesUntil(int interesting) { - if (bufferIndex == bufferLast) return null; byte what = (byte)interesting; synchronized (bufferLock) { + if (bufferIndex == bufferLast) return null; + int found = -1; for (int k = bufferIndex; k < bufferLast; k++) { if (buffer[k] == what) { @@ -530,10 +537,11 @@ public class Client implements Runnable { * @param byteBuffer passed in byte array to be altered */ public int readBytesUntil(int interesting, byte byteBuffer[]) { - if (bufferIndex == bufferLast) return 0; byte what = (byte)interesting; synchronized (bufferLock) { + if (bufferIndex == bufferLast) return 0; + int found = -1; for (int k = bufferIndex; k < bufferLast; k++) { if (buffer[k] == what) { @@ -578,8 +586,10 @@ public class Client implements Runnable { * @brief Returns the buffer as a String */ public String readString() { - if (bufferIndex == bufferLast) return null; - return new String(readBytes()); + synchronized (bufferLock) { + if (bufferIndex == bufferLast) return null; + return new String(readBytes()); + } } From e64a283a002c8c9dcd0859b07913c93f3ec1077e Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 17:03:55 +0100 Subject: [PATCH 03/14] Net-client: compact the buffer if possible instead of resizing --- java/libraries/net/src/processing/net/Client.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index 4eda3b824..da37e503b 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -236,9 +236,18 @@ public class Client implements Runnable { // todo: at some point buffer should stop increasing in size, // otherwise it could use up all the memory. if (bufferLast == buffer.length) { - byte temp[] = new byte[bufferLast << 1]; - System.arraycopy(buffer, 0, temp, 0, bufferLast); - buffer = temp; + if (bufferIndex > 0) { + // compact the buffer + int bufferLength = bufferLast - bufferIndex; + System.arraycopy(buffer, bufferIndex, buffer, 0, bufferLength); + bufferLast -= bufferIndex; + bufferIndex = 0; + } else { + // resize the buffer + byte temp[] = new byte[bufferLast << 1]; + System.arraycopy(buffer, 0, temp, 0, bufferLast); + buffer = temp; + } } buffer[bufferLast++] = (byte)value; } From e7f6e1b5b0d21c951064173c7616a7816806be25 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 21:52:57 +0100 Subject: [PATCH 04/14] Net-client: read bytes to a read buffer instead of one by one --- .../net/src/processing/net/Client.java | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index da37e503b..866d1b969 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -209,15 +209,16 @@ public class Client implements Runnable { public void run() { + byte[] readBuffer = new byte[2048]; // Ethernet MTU = 1500 B while (Thread.currentThread() == thread) { try { while (input != null) { - int value; + int readCount; // try to read a byte using a blocking read. // An exception will occur when the sketch is exits. try { - value = input.read(); + readCount = input.read(readBuffer, 0, readBuffer.length); } catch (SocketException e) { System.err.println("Client SocketException: " + e.getMessage()); // the socket had a problem reading so don't try to read from it again. @@ -226,7 +227,7 @@ public class Client implements Runnable { } // read returns -1 if end-of-stream occurs (for example if the host disappears) - if (value == -1) { + if (readCount == -1) { System.err.println("Client got end-of-stream."); stop(); return; @@ -235,31 +236,36 @@ public class Client implements Runnable { synchronized (bufferLock) { // todo: at some point buffer should stop increasing in size, // otherwise it could use up all the memory. - if (bufferLast == buffer.length) { - if (bufferIndex > 0) { - // compact the buffer - int bufferLength = bufferLast - bufferIndex; - System.arraycopy(buffer, bufferIndex, buffer, 0, bufferLength); - bufferLast -= bufferIndex; - bufferIndex = 0; - } else { - // resize the buffer - byte temp[] = new byte[bufferLast << 1]; - System.arraycopy(buffer, 0, temp, 0, bufferLast); - buffer = temp; + int freeBack = buffer.length - bufferLast; + if (readCount > freeBack) { + // not enough space at the back + int bufferLength = bufferLast - bufferIndex; + byte[] targetBuffer = buffer; + if (bufferLength + readCount > buffer.length) { + // can't fit even after compacting, resize the buffer + // find the next power of two which can fit everything in + int newSize = Integer.highestOneBit(bufferLength + readCount - 1) << 1; + targetBuffer = new byte[newSize]; } + // compact the buffer (either in-place or into the new bigger buffer) + System.arraycopy(buffer, bufferIndex, targetBuffer, 0, bufferLength); + bufferLast -= bufferIndex; + bufferIndex = 0; + buffer = targetBuffer; } - buffer[bufferLast++] = (byte)value; + // copy all newly read bytes into the buffer + System.arraycopy(readBuffer, 0, buffer, bufferLast, readCount); + bufferLast += readCount; } // now post an event if (clientEventMethod != null) { try { clientEventMethod.invoke(parent, new Object[] { this }); - } catch (Exception e) { - System.err.println("error, disabling clientEvent() for " + host); - e.printStackTrace(); - clientEventMethod = null; + } catch (Exception e) { + System.err.println("error, disabling clientEvent() for " + host); + e.printStackTrace(); + clientEventMethod = null; } } } From aba056cf96f3b01b8915fbdd1c61a5591a1d575d Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 21:55:24 +0100 Subject: [PATCH 05/14] Net-client: set max buffer size --- java/libraries/net/src/processing/net/Client.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index 866d1b969..0970e130d 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -45,6 +45,9 @@ import java.net.*; * @see_external LIB_net/clientEvent */ public class Client implements Runnable { + + protected static final int MAX_BUFFER_SIZE = 2 << 27; // 128 MB + PApplet parent; Method clientEventMethod; Method disconnectEventMethod; @@ -234,8 +237,6 @@ public class Client implements Runnable { } synchronized (bufferLock) { - // todo: at some point buffer should stop increasing in size, - // otherwise it could use up all the memory. int freeBack = buffer.length - bufferLast; if (readCount > freeBack) { // not enough space at the back @@ -245,6 +246,13 @@ public class Client implements Runnable { // can't fit even after compacting, resize the buffer // find the next power of two which can fit everything in int newSize = Integer.highestOneBit(bufferLength + readCount - 1) << 1; + if (newSize > MAX_BUFFER_SIZE) { + // buffer is full because client is not reading (fast enough) + System.err.println("Client: can't receive more data, buffer is full. " + + "Make sure you read the data from the client."); + stop(); + return; + } targetBuffer = new byte[newSize]; } // compact the buffer (either in-place or into the new bigger buffer) From 0e12d1175e73e6e30016a2d0ed6daa5edbc77944 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 21:58:48 +0100 Subject: [PATCH 06/14] Net-client: remove unnecessary array creation --- java/libraries/net/src/processing/net/Client.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index 0970e130d..cf103c39b 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -95,16 +95,14 @@ public class Client implements Runnable { // which would be called each time an event comes in try { clientEventMethod = - parent.getClass().getMethod("clientEvent", - new Class[] { Client.class }); + parent.getClass().getMethod("clientEvent", Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } // do the same for disconnectEvent(Client c); try { disconnectEventMethod = - parent.getClass().getMethod("disconnectEvent", - new Class[] { Client.class }); + parent.getClass().getMethod("disconnectEvent", Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } @@ -138,8 +136,7 @@ public class Client implements Runnable { // public void disconnectEvent(processing.net.Client) try { disconnectEventMethod = - parent.getClass().getMethod("disconnectEvent", - new Class[] { Client.class }); + parent.getClass().getMethod("disconnectEvent", Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } @@ -160,7 +157,7 @@ public class Client implements Runnable { public void stop() { if (disconnectEventMethod != null && thread != null){ try { - disconnectEventMethod.invoke(parent, new Object[] { this }); + disconnectEventMethod.invoke(parent, this); } catch (Exception e) { e.printStackTrace(); disconnectEventMethod = null; @@ -211,6 +208,7 @@ public class Client implements Runnable { } + @Override public void run() { byte[] readBuffer = new byte[2048]; // Ethernet MTU = 1500 B while (Thread.currentThread() == thread) { @@ -269,7 +267,7 @@ public class Client implements Runnable { // now post an event if (clientEventMethod != null) { try { - clientEventMethod.invoke(parent, new Object[] { this }); + clientEventMethod.invoke(parent, this); } catch (Exception e) { System.err.println("error, disabling clientEvent() for " + host); e.printStackTrace(); From f76d3c4f808ab6aa9012e9cc347ae337cc411dd8 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 22:01:42 +0100 Subject: [PATCH 07/14] Net-client: remove extra catch block Handled by IOException block (it's a superclass of ConnectException and does the same thing). --- java/libraries/net/src/processing/net/Client.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index cf103c39b..f179b6d2e 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -107,10 +107,6 @@ public class Client implements Runnable { // no such method, or an error.. which is fine, just ignore } - } catch (ConnectException ce) { - ce.printStackTrace(); - dispose(); - } catch (IOException e) { e.printStackTrace(); dispose(); From b6922157759f7f3e9d9736303ab720e2a3779a60 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 22:23:53 +0100 Subject: [PATCH 08/14] Net-server: properly synchronize clients array --- .../net/src/processing/net/Server.java | 99 +++++++++++-------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/java/libraries/net/src/processing/net/Server.java b/java/libraries/net/src/processing/net/Server.java index bf4abced2..d0ef75784 100644 --- a/java/libraries/net/src/processing/net/Server.java +++ b/java/libraries/net/src/processing/net/Server.java @@ -52,10 +52,11 @@ public class Server implements Runnable { PApplet parent; Method serverEventMethod; - Thread thread; + volatile Thread thread; ServerSocket server; int port; - + + protected final Object clientsLock = new Object[0]; /** Number of clients currently connected. */ public int clientCount; /** Array of client objects, useful length is determined by clientCount. */ @@ -127,26 +128,30 @@ public class Server implements Runnable { */ public void disconnect(Client client) { client.stop(); - int index = clientIndex(client); - if (index != -1) { - removeIndex(index); + synchronized (clientsLock) { + int index = clientIndex(client); + if (index != -1) { + removeIndex(index); + } } } protected void removeIndex(int index) { - clientCount--; - // shift down the remaining clients - for (int i = index; i < clientCount; i++) { - clients[i] = clients[i+1]; + synchronized (clientsLock) { + clientCount--; + // shift down the remaining clients + for (int i = index; i < clientCount; i++) { + clients[i] = clients[i + 1]; + } + // mark last empty var for garbage collection + clients[clientCount] = null; } - // mark last empty var for garbage collection - clients[clientCount] = null; } protected void disconnectAll() { - synchronized (clients) { + synchronized (clientsLock) { for (int i = 0; i < clientCount; i++) { try { clients[i].stop(); @@ -161,20 +166,24 @@ public class Server implements Runnable { protected void addClient(Client client) { - if (clientCount == clients.length) { - clients = (Client[]) PApplet.expand(clients); + synchronized (clientsLock) { + if (clientCount == clients.length) { + clients = (Client[]) PApplet.expand(clients); + } + clients[clientCount++] = client; } - clients[clientCount++] = client; } protected int clientIndex(Client client) { - for (int i = 0; i < clientCount; i++) { - if (clients[i] == client) { - return i; + synchronized (clientsLock) { + for (int i = 0; i < clientCount; i++) { + if (clients[i] == client) { + return i; + } } + return -1; } - return -1; } @@ -219,7 +228,7 @@ public class Server implements Runnable { * @usage application */ public Client available() { - synchronized (clients) { + synchronized (clientsLock) { int index = lastAvailable + 1; if (index >= clientCount) index = 0; @@ -293,7 +302,7 @@ public class Server implements Runnable { try { Socket socket = server.accept(); Client client = new Client(parent, socket); - synchronized (clients) { + synchronized (clientsLock) { addClient(client); if (serverEventMethod != null) { try { @@ -333,39 +342,45 @@ public class Server implements Runnable { * @param data data to write */ public void write(int data) { // will also cover char - int index = 0; - while (index < clientCount) { - if (clients[index].active()) { - clients[index].write(data); - index++; - } else { - removeIndex(index); + synchronized (clientsLock) { + int index = 0; + while (index < clientCount) { + if (clients[index].active()) { + clients[index].write(data); + index++; + } else { + removeIndex(index); + } } } } public void write(byte data[]) { - int index = 0; - while (index < clientCount) { - if (clients[index].active()) { - clients[index].write(data); - index++; - } else { - removeIndex(index); + synchronized (clientsLock) { + int index = 0; + while (index < clientCount) { + if (clients[index].active()) { + clients[index].write(data); + index++; + } else { + removeIndex(index); + } } } } public void write(String data) { - int index = 0; - while (index < clientCount) { - if (clients[index].active()) { - clients[index].write(data); - index++; - } else { - removeIndex(index); + synchronized (clientsLock) { + int index = 0; + while (index < clientCount) { + if (clients[index].active()) { + clients[index].write(data); + index++; + } else { + removeIndex(index); + } } } } From 0d12c46825fd2c274919b1f0eed95aaf1ba17544 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Sun, 21 Jan 2018 22:32:16 +0100 Subject: [PATCH 09/14] Net-server: remove extra array creation --- java/libraries/net/src/processing/net/Server.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java/libraries/net/src/processing/net/Server.java b/java/libraries/net/src/processing/net/Server.java index d0ef75784..74345800c 100644 --- a/java/libraries/net/src/processing/net/Server.java +++ b/java/libraries/net/src/processing/net/Server.java @@ -100,9 +100,7 @@ public class Server implements Runnable { // which is called when a new guy connects try { serverEventMethod = - parent.getClass().getMethod("serverEvent", - new Class[] { Server.class, - Client.class }); + parent.getClass().getMethod("serverEvent", Server.class, Client.class); } catch (Exception e) { // no such method, or an error.. which is fine, just ignore } @@ -297,6 +295,7 @@ public class Server implements Runnable { } + @Override public void run() { while (Thread.currentThread() == thread) { try { @@ -306,7 +305,7 @@ public class Server implements Runnable { addClient(client); if (serverEventMethod != null) { try { - serverEventMethod.invoke(parent, new Object[] { this, client }); + serverEventMethod.invoke(parent, this, client); } catch (Exception e) { System.err.println("Disabling serverEvent() for port " + port); e.printStackTrace(); From 2b1cd66f834c97f7e1f30aa7cfc646e51bc791a5 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Mon, 22 Jan 2018 13:44:43 +0100 Subject: [PATCH 10/14] Net: unwrap the exception if it came from the user code --- java/libraries/net/src/processing/net/Client.java | 14 ++++++++++++-- java/libraries/net/src/processing/net/Server.java | 7 ++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index f179b6d2e..2a779f96c 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -155,7 +155,12 @@ public class Client implements Runnable { try { disconnectEventMethod.invoke(parent, this); } catch (Exception e) { - e.printStackTrace(); + Throwable cause = e; + // unwrap the exception if it came from the user code + if (e instanceof InvocationTargetException && e.getCause() != null) { + cause = e.getCause(); + } + cause.printStackTrace(); disconnectEventMethod = null; } } @@ -266,7 +271,12 @@ public class Client implements Runnable { clientEventMethod.invoke(parent, this); } catch (Exception e) { System.err.println("error, disabling clientEvent() for " + host); - e.printStackTrace(); + Throwable cause = e; + // unwrap the exception if it came from the user code + if (e instanceof InvocationTargetException && e.getCause() != null) { + cause = e.getCause(); + } + cause.printStackTrace(); clientEventMethod = null; } } diff --git a/java/libraries/net/src/processing/net/Server.java b/java/libraries/net/src/processing/net/Server.java index 74345800c..f77b2e0c8 100644 --- a/java/libraries/net/src/processing/net/Server.java +++ b/java/libraries/net/src/processing/net/Server.java @@ -308,7 +308,12 @@ public class Server implements Runnable { serverEventMethod.invoke(parent, this, client); } catch (Exception e) { System.err.println("Disabling serverEvent() for port " + port); - e.printStackTrace(); + Throwable cause = e; + // unwrap the exception if it came from the user code + if (e instanceof InvocationTargetException && e.getCause() != null) { + cause = e.getCause(); + } + cause.printStackTrace(); serverEventMethod = null; } } From f6b08df336bd4489f5e98542f52cca44b5f5e528 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Mon, 22 Jan 2018 19:34:21 +0100 Subject: [PATCH 11/14] Net-server: call clientEvent() of the sketch when received data from a client --- java/libraries/net/src/processing/net/Client.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index 2a779f96c..dd03a0439 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -129,7 +129,15 @@ public class Client implements Runnable { thread.start(); // reflection to check whether host sketch has a call for - // public void disconnectEvent(processing.net.Client) + // public void clientEvent(processing.net.Client) + // which would be called each time an event comes in + try { + clientEventMethod = + parent.getClass().getMethod("clientEvent", Client.class); + } catch (Exception e) { + // no such method, or an error.. which is fine, just ignore + } + // do the same for disconnectEvent(Client c); try { disconnectEventMethod = parent.getClass().getMethod("disconnectEvent", Client.class); From bb6c9a568a9475e5ae2546e7921bcd280f856593 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Mon, 22 Jan 2018 19:50:06 +0100 Subject: [PATCH 12/14] Net-server: remove suspicious sleep --- java/libraries/net/src/processing/net/Server.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/java/libraries/net/src/processing/net/Server.java b/java/libraries/net/src/processing/net/Server.java index f77b2e0c8..e027142fa 100644 --- a/java/libraries/net/src/processing/net/Server.java +++ b/java/libraries/net/src/processing/net/Server.java @@ -327,9 +327,6 @@ public class Server implements Runnable { e.printStackTrace(); thread = null; } - try { - Thread.sleep(8); - } catch (InterruptedException ex) { } } } From fe465fe4deb6b3d14c6cfca8359791bba8ac22e8 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Mon, 22 Jan 2018 19:50:48 +0100 Subject: [PATCH 13/14] Net-client: remove unneeded synchronization block --- java/libraries/net/src/processing/net/Client.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index dd03a0439..fffa2391b 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -621,10 +621,9 @@ public class Client implements Runnable { * @brief Returns the buffer as a String */ public String readString() { - synchronized (bufferLock) { - if (bufferIndex == bufferLast) return null; - return new String(readBytes()); - } + byte b[] = readBytes(); + if (b == null) return null; + return new String(b); } From d887779eb6e69fa6f04aefb46c20cb508d3ee2a6 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Mon, 22 Jan 2018 20:28:09 +0100 Subject: [PATCH 14/14] Net-client: perf tuning - make read buf the size of socket receive buf --- java/libraries/net/src/processing/net/Client.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/java/libraries/net/src/processing/net/Client.java b/java/libraries/net/src/processing/net/Client.java index fffa2391b..61bdfa9be 100644 --- a/java/libraries/net/src/processing/net/Client.java +++ b/java/libraries/net/src/processing/net/Client.java @@ -219,7 +219,15 @@ public class Client implements Runnable { @Override public void run() { - byte[] readBuffer = new byte[2048]; // Ethernet MTU = 1500 B + byte[] readBuffer; + { // make the read buffer same size as socket receive buffer so that + // we don't waste cycles calling listeners when there is more data waiting + int readBufferSize = 2 << 16; // 64 KB (default socket receive buffer size) + try { + readBufferSize = socket.getReceiveBufferSize(); + } catch (SocketException ignore) { } + readBuffer = new byte[readBufferSize]; + } while (Thread.currentThread() == thread) { try { while (input != null) {