diff --git a/README.md b/README.md index cd6ea10..2f31e04 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ _Note: In order to use self-signed certificates make sure to [update your metro. * [`createConnection(options[, callback])`](#createconnection) * [`write(data[, encoding][, callback])`](#write) * [`destroy()`](#destroy) + * [`setNoDelay([noDelay])`](https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay) #### `createConnection()` `createConnection(options[, callback])` creates a TCP connection using the given [`options`](#createconnection-options). 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 5474bdb..371e974 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketClient.java @@ -131,4 +131,14 @@ public void close() { mReceiverListener.onClose(getId(), e.getMessage()); } } + + /** + * @param noDelay `true` will disable Nagle's algorithm for the socket (enable TCP_NODELAY) + */ + public void setNoDelay(final boolean noDelay) throws IOException { + if (socket == null) { + throw new IOException("Socket is not connected."); + } + socket.setTcpNoDelay(noDelay); + } } 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 b6f6fae..a8c437b 100644 --- a/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java +++ b/android/src/main/java/com/asterinet/react/tcpsocket/TcpSocketModule.java @@ -164,6 +164,20 @@ protected void doInBackgroundGuarded(Void... params) { }.executeOnExecutor(executorService); } + @ReactMethod + public void setNoDelay(@NonNull final Integer cId, final boolean noDelay) { + final TcpSocketClient client = socketClients.get(cId); + if (client == null) { + onError(cId, TAG + "socket not found."); + return; + } + try { + client.setNoDelay(noDelay); + } catch (IOException e) { + onError(cId, e.getMessage()); + } + } + private void requestNetwork(final int transportType) throws InterruptedException { final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder(); requestBuilder.addTransportType(transportType); diff --git a/ios/TcpSocketClient.h b/ios/TcpSocketClient.h index 5706f0b..672ee89 100644 --- a/ios/TcpSocketClient.h +++ b/ios/TcpSocketClient.h @@ -92,5 +92,6 @@ typedef enum RCTTCPError RCTTCPError; */ - (void)destroy; +- (void)setNoDelay:(BOOL)noDelay; @end diff --git a/ios/TcpSocketClient.m b/ios/TcpSocketClient.m index 4df8096..a6105f2 100644 --- a/ios/TcpSocketClient.m +++ b/ios/TcpSocketClient.m @@ -1,4 +1,5 @@ #import +#import #import #import "TcpSocketClient.h" @@ -124,6 +125,18 @@ - (BOOL)connect:(NSString *)host port:(int)port withOptions:(NSDictionary *)opti @"family": @"unkown" }; } +- (void)setNoDelay:(BOOL)noDelay +{ + [_tcpSocket performBlock:^{ + int fd = [self->_tcpSocket socketFD]; + int on = noDelay ? 1 : 0; + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on)) == -1) { + /* TODO: handle error */ + RCTLogWarn(@"setNoDelay caused an unexpected error"); + } + }]; +} + - (BOOL)listen:(NSDictionary *)options error:(NSError **)error { if (_tcpSocket) { diff --git a/ios/TcpSockets.m b/ios/TcpSockets.m index 81473cb..166ea54 100644 --- a/ios/TcpSockets.m +++ b/ios/TcpSockets.m @@ -116,6 +116,13 @@ - (TcpSocketClient *)createSocket:(nonnull NSNumber*)cId } } +RCT_EXPORT_METHOD(setNoDelay:(nonnull NSNumber*)cId noDelay:(BOOL)noDelay) { + TcpSocketClient* client = [self findClient:cId]; + if (!client) return; + + [client setNoDelay:noDelay]; +} + - (void)onConnect:(TcpSocketClient*) client { [self sendEventWithName:@"connect" diff --git a/src/TcpSocket.js b/src/TcpSocket.js index a08f818..0c1570b 100644 --- a/src/TcpSocket.js +++ b/src/TcpSocket.js @@ -204,6 +204,19 @@ export default class TcpSocket { return this; } + /** + * Enable/disable the use of Nagle's algorithm. When a TCP connection is created, it will have Nagle's algorithm enabled. + * + * Nagle's algorithm delays data before it is sent via the network. It attempts to optimize throughput at the expense of latency. + * + * Passing `true` for `noDelay` or not passing an argument will disable Nagle's algorithm for the socket. Passing false for noDelay will enable Nagle's algorithm. + * + * @param {boolean} noDelay + */ + setNoDelay(noDelay = true) { + Sockets.setNoDelay(this._id, noDelay); + } + address() { return this._address; }