ReadableByteChannel.read(ByteBuffer dest) reads capped at 8KB. Why?
I've got some code that:
- reads from a
ReadableByteChannel
into aByteBuffer
, - takes note of the bytes transfered,
- pauses a few tens to hundreds of miliseconds,
- passes the
ByteBuffer
onto aWritableByteChannel
.
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 l开发者_C百科ike, 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?
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.
精彩评论