我正在使用Java的BufferedInputStream
类来读取发送到套接字的字节。
套接字的数据是HTTP格式,因此通常是具有已定义内容长度的标头,然后是一些内容。
我遇到的问题是有时BufferedInputStream.read()
无法读取发送给它的全部数据。它返回读取的字节数,但这比发送的要少得多。我已经验证了Wireshark发送的字节,并且可以确认正在传输完整的消息。)
以下示例代码:
BufferedInputStream inFromClient = new BufferedInputStream(socket.getInputStream());
int contentLength = getContentLengthFromHeader();
byte[] b = new byte[contentLength];
int bytesRead = inFromClient.read(b, 0, contentLength);
一旦read()完成,有时bytesRead
等于contentLength
,但在其他情况下,read()似乎不会读到内容的结尾。
有没有人对正在发生的事情有任何想法? Java缓冲输出?是否有更好的方法从套接字读取?
答案 0 :(得分:1)
您假设read()
填充缓冲区。检查Javadoc。它传输至少一个字节,就是它所说的。
您不需要大缓冲区和BufferedInputStream.
将后者更改为DataInputStream.readFully().
答案 1 :(得分:0)
这是read()方法的正常行为:您需要继续读取循环,直到读取返回-1。 (参见http://docs.oracle.com/javase/7/docs/api/java/io/BufferedInputStream.html#read(byte [],%20int,%20int))
一般情况下,这是因为read方法试图在阻塞之前将所有数据返回给你,而不是你将获得的所有数据。
我经常使用一些实用方法来处理这类事情:(剪掉了上下文 - 注意我不是channelCopy方法的作者,但是来源是归属的)
/**
* Efficiently copy from an InputStream to an OutputStream; uses channels and
* direct buffering for a faster copy than oldCopy.
* @param in - non-null readable inputstream
* @param out - non-null writeable outputstream
* @throws IOException if unable to read or write for some reason.
*/
public static void streamCopy(InputStream in, OutputStream out) throws IOException {
assert (in != null);
assert (out != null);
ReadableByteChannel inChannel = Channels.newChannel(in);
WritableByteChannel outChannel = Channels.newChannel(out);
channelCopy(inChannel, outChannel);
}
/**
* Read the *BINARY* data from an InputStream into an array of bytes. Don't
* use this for text.
* @param is - non-null InputStream
* @return a byte array with the all the bytes provided by the InputStream
* until it reaches EOF.
* @throws IOException
*/
public static byte[] getBytes(InputStream is) throws IOException{
ByteArrayOutputStream os = new ByteArrayOutputStream();
streamCopy(is, os);
return os.toByteArray();
}
/**
* A fast method to copy bytes from one channel to another; uses direct 16k
* buffers to minimize copies and OS overhead.
* @author http://thomaswabner.wordpress.com/2007/10/09/fast-stream-copy-using-javanio-channels/
* @param src - a non-null readable bytechannel to read the data from
* @param dest - a non-null writeable byte channel to write the data to
*/
public static void channelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {
assert (src != null);
assert (dest != null);
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1) {
// prepare the buffer to be drained
buffer.flip();
// write to the channel, may block
dest.write(buffer);
// If partial transfer, shift remainder down
// If buffer is empty, same as doing clear()
buffer.compact();
}
// EOF will leave buffer in fill state
buffer.flip();
// make sure the buffer is fully drained.
while (buffer.hasRemaining()) {
dest.write(buffer);
}
}