使用BufferedInputStream读取套接字

Ada*_*dam 5 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);
Run Code Online (Sandbox Code Playgroud)

一旦read()完成,有时bytesRead等于contentLength但在其他情况下read()似乎不会读到内容的结尾.有没有人对正在发生的事情有任何想法?Java缓冲输出?有更好的方法从套接字读取?

JVM*_*ATL 0

这是 read() 方法的正常行为:您需要继续循环读取,直到 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);
      }
  }
Run Code Online (Sandbox Code Playgroud)