使用BufferedInputStream读取套接字

时间:2014-01-13 22:04:56

标签: java sockets http bufferedinputstream

我正在使用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缓冲输出?是否有更好的方法从套接字读取?

2 个答案:

答案 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);
      }
  }
相关问题