Skip to content

Commit 31dcbc1

Browse files
committed
replaced byte[] with ByteBuffer in order to ( be able to ) spare memory allocations
improved Draft75/76 framing performance
1 parent e2a017f commit 31dcbc1

16 files changed

+152
-72
lines changed

example/AutobahnClientTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import java.io.IOException;
33
import java.io.InputStreamReader;
44
import java.net.URI;
5+
import java.nio.ByteBuffer;
56

67
import org.java_websocket.WebSocket;
78
import org.java_websocket.WebSocketClient;
@@ -135,7 +136,7 @@ public void onMessage( String message ) {
135136
}
136137

137138
@Override
138-
public void onMessage( byte[] blob ) {
139+
public void onMessage( ByteBuffer blob ) {
139140
try {
140141
getConnection().send( blob );
141142
} catch ( InterruptedException e ) {

example/AutobahnServerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import java.net.InetSocketAddress;
22
import java.net.UnknownHostException;
3+
import java.nio.ByteBuffer;
34

45
import org.java_websocket.WebSocket;
56
import org.java_websocket.WebSocketServer;
@@ -44,7 +45,7 @@ public void onMessage( WebSocket conn, String message ) {
4445
}
4546

4647
@Override
47-
public void onMessage( WebSocket conn, byte[] blob ) {
48+
public void onMessage( WebSocket conn, ByteBuffer blob ) {
4849
try {
4950
conn.send( blob );
5051
} catch ( InterruptedException e ) {

example/ChatServer.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.net.InetAddress;
55
import java.net.InetSocketAddress;
66
import java.net.UnknownHostException;
7+
import java.util.Set;
78

89
import org.java_websocket.WebSocket;
910
import org.java_websocket.WebSocketServer;
@@ -17,15 +18,15 @@ public class ChatServer extends WebSocketServer {
1718
public ChatServer( int port ) throws UnknownHostException {
1819
super( new InetSocketAddress( InetAddress.getByName( "localhost" ), port ) );
1920
}
20-
21+
2122
public ChatServer( InetSocketAddress address ) {
2223
super( address );
2324
}
2425

2526
@Override
2627
public void onOpen( WebSocket conn, ClientHandshake handshake ) {
2728
try {
28-
this.sendToAll( conn + " entered the room!" );
29+
this.sendToAll( "new" );
2930
} catch ( InterruptedException ex ) {
3031
ex.printStackTrace();
3132
}
@@ -45,7 +46,7 @@ public void onClose( WebSocket conn, int code, String reason, boolean remote ) {
4546
@Override
4647
public void onMessage( WebSocket conn, String message ) {
4748
try {
48-
this.sendToAll( conn + ": " + message );
49+
this.sendToAll( message );
4950
} catch ( InterruptedException ex ) {
5051
ex.printStackTrace();
5152
}
@@ -84,8 +85,11 @@ public void onError( WebSocket conn, Exception ex ) {
8485
* When socket related I/O errors occur.
8586
*/
8687
public void sendToAll( String text ) throws InterruptedException {
87-
for( WebSocket c : connections() ) {
88-
c.send( text );
88+
Set<WebSocket> con = connections();
89+
synchronized ( con ) {
90+
for( WebSocket c : con ) {
91+
c.send( text );
92+
}
8993
}
9094
}
9195
}

src/org/java_websocket/WebSocket.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ public void close( InvalidDataException e ) {
446446
* @throws InterruptedException
447447
* @throws NotYetConnectedException
448448
*/
449-
public void send( String text ) throws IllegalArgumentException , NotYetConnectedException , InterruptedException {
449+
public void send( String text ) throws NotYetConnectedException , InterruptedException {
450450
if( text == null )
451451
throw new IllegalArgumentException( "Cannot send 'null' data to a WebSocket." );
452452
send( draft.createFrames( text, role == Role.CLIENT ) );
@@ -459,12 +459,16 @@ public void send( String text ) throws IllegalArgumentException , NotYetConnecte
459459
* @throws InterruptedException
460460
* @throws NotYetConnectedException
461461
*/
462-
public void send( byte[] bytes ) throws IllegalArgumentException , NotYetConnectedException , InterruptedException {
462+
public void send( ByteBuffer bytes ) throws IllegalArgumentException , NotYetConnectedException , InterruptedException {
463463
if( bytes == null )
464464
throw new IllegalArgumentException( "Cannot send 'null' data to a WebSocket." );
465465
send( draft.createFrames( bytes, role == Role.CLIENT ) );
466466
}
467467

468+
public void send( byte[] bytes ) throws IllegalArgumentException , NotYetConnectedException , InterruptedException {
469+
send( ByteBuffer.wrap( bytes ) );
470+
}
471+
468472
private void send( Collection<Framedata> frames ) throws InterruptedException {
469473
if( !this.handshakeComplete )
470474
throw new NotYetConnectedException();
@@ -504,13 +508,13 @@ long bufferedDataAmount() {
504508
public void flush() throws IOException {
505509
ByteBuffer buffer = this.bufferQueue.peek();
506510
while ( buffer != null ) {
507-
sockchannel.write( buffer );
511+
int written = sockchannel.write( buffer );
508512
if( buffer.remaining() > 0 ) {
509513
continue;
510514
} else {
511515
synchronized ( bufferQueueTotalAmount ) {
512516
// subtract this amount of data from the total queued (synchronized over this object)
513-
bufferQueueTotalAmount -= buffer.limit();
517+
bufferQueueTotalAmount -= written;
514518
}
515519
this.bufferQueue.poll(); // Buffer finished. Remove it.
516520
buffer = this.bufferQueue.peek();
@@ -557,11 +561,10 @@ public void startHandshake( ClientHandshakeBuilder handshakedata ) throws Invali
557561

558562
private void channelWrite( ByteBuffer buf ) throws InterruptedException {
559563
if( DEBUG )
560-
System.out.println( "write(" + buf.limit() + "): {" + ( buf.limit() > 1000 ? "too big to display" : new String( buf.array() ) ) + "}" );
561-
buf.rewind(); // TODO rewinding should not be nessesary
564+
System.out.println( "write(" + buf.remaining() + "): {" + ( buf.remaining() > 1000 ? "too big to display" : new String( buf.array() ) ) + "}" );
562565
synchronized ( bufferQueueTotalAmount ) {
563566
// add up the number of bytes to the total queued (synchronized over this object)
564-
bufferQueueTotalAmount += buf.limit();
567+
bufferQueueTotalAmount += buf.remaining();
565568
}
566569
if( !bufferQueue.offer( buf ) ) {
567570
try {

src/org/java_websocket/WebSocketAdapter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.java_websocket;
22

3+
import java.nio.ByteBuffer;
4+
35
import org.java_websocket.drafts.Draft;
46
import org.java_websocket.exeptions.InvalidDataException;
57
import org.java_websocket.framing.Framedata;
@@ -74,7 +76,7 @@ public void onWebsocketClose( WebSocket conn, int code, String reason, boolean r
7476
* @see @see org.java_websocket.WebSocketListener#onWebsocketMessage(WebSocket, byte[])
7577
*/
7678
@Override
77-
public void onWebsocketMessage( WebSocket conn, byte[] blob ) {
79+
public void onWebsocketMessage( WebSocket conn, ByteBuffer blob ) {
7880
}
7981

8082
/**

src/org/java_websocket/WebSocketClient.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.IOException;
44
import java.net.InetSocketAddress;
55
import java.net.URI;
6+
import java.nio.ByteBuffer;
67
import java.nio.channels.ClosedByInterruptException;
78
import java.nio.channels.NotYetConnectedException;
89
import java.nio.channels.SelectionKey;
@@ -314,7 +315,7 @@ public final void onWebsocketMessage( WebSocket conn, String message ) {
314315
}
315316

316317
@Override
317-
public final void onWebsocketMessage( WebSocket conn, byte[] blob ) {
318+
public final void onWebsocketMessage( WebSocket conn, ByteBuffer blob ) {
318319
onMessage( blob );
319320
}
320321

@@ -363,6 +364,6 @@ public WebSocket getConnection() {
363364
public abstract void onMessage( String message );
364365
public abstract void onClose( int code, String reason, boolean remote );
365366
public abstract void onError( Exception ex );
366-
public void onMessage( byte[] bytes ) {
367+
public void onMessage( ByteBuffer bytes ) {
367368
};
368369
}

src/org/java_websocket/WebSocketListener.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.java_websocket;
22

3+
import java.nio.ByteBuffer;
4+
35
import org.java_websocket.drafts.Draft;
46
import org.java_websocket.exeptions.InvalidDataException;
57
import org.java_websocket.framing.Framedata;
@@ -79,7 +81,7 @@ public interface WebSocketListener {
7981
* @param blob
8082
* The binary message that was received.
8183
*/
82-
public void onWebsocketMessage( WebSocket conn, byte[] blob );
84+
public void onWebsocketMessage( WebSocket conn, ByteBuffer blob );
8385

8486
/**
8587
* Called after <var>onHandshakeReceived</var> returns <var>true</var>.

src/org/java_websocket/WebSocketServer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.net.InetAddress;
55
import java.net.InetSocketAddress;
66
import java.net.UnknownHostException;
7+
import java.nio.ByteBuffer;
78
import java.nio.channels.SelectionKey;
89
import java.nio.channels.Selector;
910
import java.nio.channels.ServerSocketChannel;
@@ -258,7 +259,7 @@ public final void onWebsocketMessage( WebSocket conn, String message ) {
258259
}
259260

260261
@Override
261-
public final void onWebsocketMessage( WebSocket conn, byte[] blob ) {
262+
public final void onWebsocketMessage( WebSocket conn, ByteBuffer blob ) {
262263
onMessage( conn, blob );
263264
}
264265

@@ -299,7 +300,7 @@ public final void onWriteDemand( WebSocket conn ) {
299300
public abstract void onClose( WebSocket conn, int code, String reason, boolean remote );
300301
public abstract void onMessage( WebSocket conn, String message );
301302
public abstract void onError( WebSocket conn, Exception ex );
302-
public void onMessage( WebSocket conn, byte[] message ) {
303+
public void onMessage( WebSocket conn, ByteBuffer message ) {
303304
};
304305

305306
}

src/org/java_websocket/drafts/Draft.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public enum CloseHandshakeType {
4040
NONE, ONEWAY, TWOWAY
4141
}
4242

43+
public static int MAX_FAME_SIZE = 1000 * 1;
44+
public static int INITIAL_FAMESIZE = 64;
45+
4346
public static final byte[] FLASH_POLICY_REQUEST = Charsetfunctions.utf8Bytes( "<policy-file-request/>\0" );
4447
private static Pattern getpattern = Pattern.compile( "" ); // GET / HTTP/1.1
4548
private static Pattern statuspattern = Pattern.compile( "" ); // HTTP/1.1 101 Switching Protocols
@@ -118,7 +121,7 @@ protected boolean basicAccept( Handshakedata handshakedata ) {
118121

119122
public abstract ByteBuffer createBinaryFrame( Framedata framedata ); // TODO Allow to send data on the base of an Iterator or InputStream
120123

121-
public abstract List<Framedata> createFrames( byte[] binary, boolean mask );
124+
public abstract List<Framedata> createFrames( ByteBuffer binary, boolean mask );
122125

123126
public abstract List<Framedata> createFrames( String text, boolean mask );
124127

@@ -167,6 +170,8 @@ public List<ByteBuffer> createHandshake( Handshakedata handshakedata, Role ownro
167170

168171
public abstract List<Framedata> translateFrame( ByteBuffer buffer ) throws InvalidDataException;
169172

173+
public abstract CloseHandshakeType getCloseHandshakeType();
174+
170175
public Handshakedata translateHandshake( ByteBuffer buf ) throws InvalidHandshakeException {
171176
return translateHandshakeHttp( buf, role );
172177
}
@@ -181,6 +186,4 @@ public void setParseMode( Role role ) {
181186
this.role = role;
182187
}
183188

184-
public abstract CloseHandshakeType getCloseHandshakeType();
185-
186189
}

src/org/java_websocket/drafts/Draft_10.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@ public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) t
8282

8383
@Override
8484
public ByteBuffer createBinaryFrame( Framedata framedata ) {
85-
byte[] mes = framedata.getPayloadData();
85+
ByteBuffer mes = framedata.getPayloadData();
8686
boolean mask = role == Role.CLIENT; // framedata.getTransfereMasked();
87-
int sizebytes = mes.length <= 125 ? 1 : mes.length <= 65535 ? 2 : 8;
88-
ByteBuffer buf = ByteBuffer.allocate( 1 + ( sizebytes > 1 ? sizebytes + 1 : sizebytes ) + ( mask ? 4 : 0 ) + mes.length );
87+
int sizebytes = mes.remaining() <= 125 ? 1 : mes.remaining() <= 65535 ? 2 : 8;
88+
ByteBuffer buf = ByteBuffer.allocate( 1 + ( sizebytes > 1 ? sizebytes + 1 : sizebytes ) + ( mask ? 4 : 0 ) + mes.remaining() );
8989
byte optcode = fromOpcode( framedata.getOpcode() );
9090
byte one = (byte) ( framedata.isFin() ? -128 : 0 );
9191
one |= optcode;
9292
buf.put( one );
93-
byte[] payloadlengthbytes = toByteArray( mes.length, sizebytes );
93+
byte[] payloadlengthbytes = toByteArray( mes.remaining(), sizebytes );
9494
assert ( payloadlengthbytes.length == sizebytes );
9595

9696
if( sizebytes == 1 ) {
@@ -108,8 +108,8 @@ public ByteBuffer createBinaryFrame( Framedata framedata ) {
108108
ByteBuffer maskkey = ByteBuffer.allocate( 4 );
109109
maskkey.putInt( new Random().nextInt() );
110110
buf.put( maskkey.array() );
111-
for( int i = 0 ; i < mes.length ; i++ ) {
112-
buf.put( (byte) ( mes[ i ] ^ maskkey.get( i % 4 ) ) );
111+
for( int i = 0 ; i < mes.limit() ; i++ ) {
112+
buf.put( (byte) ( mes.get() ^ maskkey.get( i % 4 ) ) );
113113
}
114114
} else
115115
buf.put( mes );
@@ -121,7 +121,7 @@ public ByteBuffer createBinaryFrame( Framedata framedata ) {
121121
}
122122

123123
@Override
124-
public List<Framedata> createFrames( byte[] binary, boolean mask ) {
124+
public List<Framedata> createFrames( ByteBuffer binary, boolean mask ) {
125125
FrameBuilder curframe = new FramedataImpl1();
126126
try {
127127
curframe.setPayload( binary );
@@ -137,9 +137,8 @@ public List<Framedata> createFrames( byte[] binary, boolean mask ) {
137137
@Override
138138
public List<Framedata> createFrames( String text, boolean mask ) {
139139
FrameBuilder curframe = new FramedataImpl1();
140-
byte[] pay = Charsetfunctions.utf8Bytes( text );
141140
try {
142-
curframe.setPayload( pay );
141+
curframe.setPayload( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( text ) ) );
143142
} catch ( InvalidDataException e ) {
144143
throw new NotSendableException( e );
145144
}
@@ -282,16 +281,15 @@ public List<Framedata> translateFrame( ByteBuffer buffer ) throws LimitExedeedEx
282281
buffer.reset();
283282
int pref = e.getPreferedSize();
284283
incompleteframe = ByteBuffer.allocate( checkAlloc( pref ) );
285-
incompleteframe.put( buffer.array(), buffer.position(), buffer.remaining() );
286-
buffer.position( buffer.position() + buffer.remaining() );
284+
incompleteframe.put( buffer );
287285
break;
288286
}
289287
}
290288
return frames;
291289
}
292290

293291
public Framedata translateSingleFrame( ByteBuffer buffer ) throws IncompleteException , InvalidDataException {
294-
int maxpacketsize = buffer.limit() - buffer.position();
292+
int maxpacketsize = buffer.remaining();
295293
int realpacketsize = 2;
296294
if( maxpacketsize < realpacketsize )
297295
throw new IncompleteException( realpacketsize );
@@ -369,7 +367,8 @@ public Framedata translateSingleFrame( ByteBuffer buffer ) throws IncompleteExce
369367
frame.setFin( FIN );
370368
frame.setOptcode( optcode );
371369
}
372-
frame.setPayload( payload.array() );
370+
payload.flip();
371+
frame.setPayload( payload );
373372
return frame;
374373
}
375374

0 commit comments

Comments
 (0)