read()方法:如果没有可获取的字节,将会阻塞。
源码
/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the stream
* has been reached, the value <code>-1</code> is returned. This method
* blocks until input data is available, the end of the stream is detected,
* or an exception is thrown.
*
* <p> A subclass must provide an implementation of this method.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
*/
public abstract int read() throws IOException;
available()方法。
/**
* Returns an estimate of the number of bytes that can be read (or
* skipped over) from this input stream without blocking by the next
* invocation of a method for this input stream. The next invocation
* might be the same thread or another thread. A single read or skip of this
* many bytes will not block, but may read or skip fewer bytes.
*
* <p> Note that while some implementations of {@code InputStream} will return
* the total number of bytes in the stream, many will not. It is
* never correct to use the return value of this method to allocate
* a buffer intended to hold all data in this stream.
*
* <p> A subclass' implementation of this method may choose to throw an
* {@link IOException} if this input stream has been closed by
* invoking the {@link #close()} method.
*
* <p> The {@code available} method for class {@code InputStream} always
* returns {@code 0}.
*
* <p> This method should be overridden by subclasses.
*
* @return an estimate of the number of bytes that can be read (or skipped
* over) from this input stream without blocking or {@code 0} when
* it reaches the end of the input stream.
* @exception IOException if an I/O error occurs.
*/
public int available() throws IOException {
return 0;
}
大概意思是:注意,一些实现方法将返回流的全部的字节数,有一些方法则不会,想通过这个方法的返回值来分配缓冲区的长度,来承接流的全部数据,这样是不正确。
尽量不使用available方法,如果使用真的需要使用,在available方法使用之前使用一次read,想下面这样。
//将接收到的数据存到字节数组bytes
int firstByte = inputStream.read();
int length = inputStream.available();
byte[] bytes = new byte[length+1];
bytes[0] = (byte)firstByte;
inputStream.read(bytes,1,length);
知乎上有一段是这样的。供参考
read的文档说明大致是:如果因已到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流的末尾或者抛出异常前,此方法一直阻塞。 socket和文件不一样,从文件中读,读到末尾就到达流的结尾了,所以会返回-1或null,循环结束,但是socket是连接两个主机的桥梁,一端无法知道另一端到底还有没有数据要传输。 socket如果不关闭的话,read之类的阻塞函数会一直等待它发送数据,就是所谓的阻塞。如果发送的东西非常多必须要用循环读的话,可以有一下解决方案:
①在写方调用socket的shutdownOutput方法关闭输出流,该方法的文档说明为,将此套接字的输出流置于“流的末尾”,这样另一端的输入流上的read操作就会返回-1。但是这样不能实现多次交互。
②约定结束标志,当读到该结束标志时退出不再read。
③设置超时,会在设置的超时时间到达后抛出SocketTimeoutException异常而不再阻塞。
④双方定义好通信协议,在协议头部约定好数据的长度。当读取到的长度等于这个长度时就不再继续调用read方法。
作者:qhyuan
链接:https://www.zhihu.com/question/39851782/answer/86588005
来源:知乎