views:

27

answers:

1

I've got some code that:

  1. reads from a ReadableByteChannel into a ByteBuffer,
  2. takes note of the bytes transfered,
  3. pauses a few tens to hundreds of miliseconds,
  4. passes the ByteBuffer onto a WritableByteChannel.

Some details:

  • Both Channels are TCP/IP sockets.
  • The total connection read size is in the tens of megabytes.
  • The source socket (which the ReadableByteChannel is getting bytes from) is on the same machine.
  • Debian Lenny 64-bit on HP DL380s
  • Sun Java 1.6.0 update 20

The problem is, no matter how large a ByteBuffer is allocated, either with .allocate() or .allocateDirect(), the number of bytes read into the ByteBuffer maxes out at 8KB. My target ByteBuffer size is 256KB, which is only a tiny fraction (1/32nd) is being used. About 10% of the time only 2896 bytes are read in.

I've checked the OS TCP buffer settings, and they look fine. This is confirmed by watching netstat's report on how many bytes are in the buffer--both have data in the socket buffers exceeding 8KB.

tcp        0 192384 1.2.3.4:8088     1.2.3.4:53404    ESTABLISHED
tcp6  110144      0 1.2.3.4:53404    1.2.3.4:8088     ESTABLISHED

One thing that stands out here is the mix of TCP and TCP6, but that should not be a problem, I think. My Java client is on port 53404 in the above output.

I've tried setting the socket properties to favor bandwidth over latency, but no change.

Socket socket = new Socket(host.getHostName(), host.getPort());
socket.setPerformancePreferences(1, 0, 2);  //bw > connection time > latency

When I log the value of socket.getReceiveBufferSize(), it consistently reports a mere 43856 bytes. While it is smaller than I would like, it is still more than 8KB. (It is also is not a very round number, which I would have expected.)

I'm really stumped as to what the problem is here. In theory, AFAIK, this should not be happening. It would not be desirable to 'downgrade' to a stream-based solution, although that is where we are going next if a solution cannot be found.

What am I missing? What can I do to correct it?

A: 

OK, I've found the issue! (And am answer my own question in case someone has the same problem.)

I was instancing the ReadableByteChannel not directly from the Socket instance, but from an the HttpEntity.getContent() (Apache HTTP Commons Client) method's returned InputStream. The HTTP Commons client had been passed the socket early on with the DefaultHttpClientConnection.bind() method. What I did not understand is, I think, the Channel is of a BufferedInputStream instance buried inside the HTTP Commons Client implementation. (8KB just happens to be the default value for a Java 6.)

My solution, therefore, was to grab the ReadableByteChannel off the raw Socket instance.

Stu Thompson