Socket reading using BufferedInputStream

喜欢而已 提交于 2019-12-10 14:06:57

问题


I'm using Java's BufferedInputStream class to read bytes sent to a socket. The data to the socket is HTTP form so generally is a header with defined content-length, then some content.

The problem I'm having is that sometimes BufferedInputStream.read() will not read the full amount of data sent to it. It returns the number of bytes read but this is much less than has been sent. I have verified the bytes sent with Wireshark and can confirm the full message is being transmitted.)

Sample code below:

BufferedInputStream inFromClient = new BufferedInputStream(socket.getInputStream());
int contentLength = getContentLengthFromHeader();    
byte[] b = new byte[contentLength];
int bytesRead = inFromClient.read(b, 0, contentLength);

Once read() is finished sometimes bytesRead is equal to contentLength but on other occasions read() does not seem to read as far as the end of the content. Does anyone have any ideas on what is happening? Is Java buffering output? Are there better ways of reading from sockets?


回答1:


You're assuming that read() fills the buffer. Check the Javadoc. It transfers at least one byte, that's all it says.

You don't need both a large buffer and a BufferedInputStream. Change the latter to DataInputStream.readFully().




回答2:


This is normal behavior for the read() method: you need to keep reading in a loop until read returns -1. (see http://docs.oracle.com/javase/7/docs/api/java/io/BufferedInputStream.html#read(byte[],%20int,%20int))

In general, it happens because the read method is trying to return all the data it can to you before blocking, not all the data you will ever get.

There are a couple of utility methods I frequently use for this sort of thing: (snipped out of context - note that I am not the author of the channelCopy method, but the source is attributed)

   /**
    * 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);
      }
  }


来源:https://stackoverflow.com/questions/21102299/socket-reading-using-bufferedinputstream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!