Without creating additional threads, create a ServerSocket on a random unused port, a client Socket connecting to localhost and a server Socket.
Part 1) Send messages from client to server and back again. (This can be useful in unit tests)
[Click for sample solution]
ServerSocket ss = new ServerSocket(0);
Socket c = new Socket("localhost", ss.getLocalPort());
Socket s= ss.accept();
ss.close();
// sends one byte.
c.getOutputStream().write(1);
int num = s.getInputStream().read();
s.getOutputStream().write(num+1);
int num2 = c.getInputStream().read();
s.close();
c.close();
Part 2) Do the same with blocking NIO.
[Click for sample solution]
ServerSocketChannel ss = ServerSocketChannel.open();
ss.socket().bind(new InetSocketAddress(0));
SocketChannel c = SocketChannel.open(new InetSocketAddress("localhost", ss.socket().getLocalPort()));
SocketChannel s = ss.accept();
ss.close();
// sends one byte.
ByteBuffer bb1 = ByteBuffer.allocateDirect(1);
c.write(bb1);
// read one byte.
ByteBuffer bb2 = ByteBuffer.allocateDirect(1);
int num = s.read(bb2);
// sends it back.
bb2.flip();
s.write(bb2);
// reads one byte.
bb1.clear();
c.read(bb1);
s.close();
c.close();
Part 3) Benchmark how many GB/s per second you can transfer this way.
[Click for sample solution]
ServerSocketChannel ss = ServerSocketChannel.open();
ss.socket().bind(new InetSocketAddress(0));
SocketChannel c = SocketChannel.open(new InetSocketAddress("localhost", ss.socket().getLocalPort()));
SocketChannel s = ss.accept();
ss.close();
final int bufferSize = 64 * 1024;
final int runs = 10000;
for (int j = 0; j < 3; j++) {
ByteBuffer bb1 = ByteBuffer.allocateDirect(bufferSize);
ByteBuffer bb2 = ByteBuffer.allocateDirect(bufferSize);
long start = System.nanoTime();
for (int i = 0; i < runs; i++) {
// sends one buffer.
bb1.clear();
c.write(bb1);
// read one buffer.
bb2.clear();
int num = s.read(bb2);
// sends it back.
bb2.flip();
s.write(bb2);
// reads one byte.
bb1.clear();
c.read(bb1);
}
long time = System.nanoTime() - start;
long rate = (long) (1e9 * bufferSize * runs / time / 1e6);
System.out.println("Transfer rate " + rate + " MB/s");
}
s.close();
c.close();
Prints on my machine
Transfer rate 1963 MB/s
Transfer rate 2330 MB/s
Transfer rate 2365 MB/s
Part 4) Measure the typical and 99.99% round trip latency, and estimate how much garbage is produced.
For bonus points try the same with Async NIO2 in Java 7.
I will add a solution Nov 29th (after a week)
loopback Blocking socket/NIO the same ~65(in or out) Mb/s with payload 1460 bytes
ReplyDeletenetwork Blocking socket/NIO ~1/0.7 Мb/s with payload 1460 bytes
@Unknown, Are you sure that Mb/s and not MB/s? Even so I would expect 65 MB/s or more on a 1 GB ethernet.
ReplyDeleteMb - means megabyte not megabit.
ReplyDeleteIt quite common to write network bandwidth as 100 Mb/s per 1 Gb/s (b for bits) where as disk transfer rates are usually in MB/s (B for bytes)
ReplyDeleteIEEE-1541 recommends b for bits and B for bytes.