最近写在网络编程这块的代码,发现了一个我之前没有注意到的一个点。read函数的读取。
在使用读取文件的时候,最终就会调用以下的函数
int read(byte b[], int off, int length, int timeout) throws IOException {
int n;
// EOF already encountered 是否到了文件尾部
if (eof) {
return -1;
}
// connection reset 判断网络是否在重新连接
if (impl.isConnectionReset()) {
throw new SocketException("Connection reset");
}
// bounds check 检查参数合法性
if (length <= 0 || off < 0 || length > b.length - off) {
if (length == 0) {
return 0;
}
throw new ArrayIndexOutOfBoundsException("length == " + length
+ " off == " + off + " buffer length == " + b.length);
}
boolean gotReset = false; //说明在连接中
// acquire file descriptor and do the read 获取文件描述符并进行读取
FileDescriptor fd = impl.acquireFD();
try {
n = socketRead(fd, b, off, length, timeout); //读取长度,但是这里并不保证读取的长度一定是len
if (n > 0) {
return n;
}
} catch (ConnectionResetException rstExc) {
gotReset = true;
} finally {
impl.releaseFD();
}
/*
* We receive a "connection reset" but there may be bytes still
* buffered on the socket
*/
if (gotReset) {
impl.setConnectionResetPending();
impl.acquireFD();
try {
n = socketRead(fd, b, off, length, timeout);
if (n > 0) {
return n;
}
} catch (ConnectionResetException rstExc) {
} finally {
impl.releaseFD();
}
}
/*
* If we get here we are at EOF, the socket has been closed,
* or the connection has been reset.
*/
if (impl.isClosedOrPending()) {
throw new SocketException("Socket closed");
}
if (impl.isConnectionResetPending()) {
impl.setConnectionReset();
}
if (impl.isConnectionReset()) {
throw new SocketException("Connection reset");
}
eof = true;
return -1;
}
我们在代码中可以看到,在read中,传进去一个长度为10的byte[],但实际上并不会一定读到10个字节的数据,这可能跟网络有关,可能对端并没有传输过来这些数据,所以可能只读到了8个字节就返回了,那么我们应该如何解决这个问题呢?
protected byte[] receive(InputStream in, int length) throws IOException {
byte[] bytes = new byte[length];
int cur = 0; //当前的长度
int offset = 0; //当前的偏移量
int restLen = length; //控制循环
while (restLen > 0) { //没有接收到足够的长度,就一直自旋下去
cur = restLen > length? length: restLen; //给cur赋值,根据当前大小进行赋值
cur = in.read(bytes, offset, cur); // 在bytes中,从offset处开始读,读取cur的长度,返回真正读取的长度
offset += cur; // offset右移
restLen -= cur;
}
return bytes;
}