In-depth understanding of IO mode under LINUX (2) - what is stream-oriented and what is buffer-oriented

Stream-oriented, buffer-oriented, this is a concept in JAVA, and it has nothing to do with the operating system


.


java.net.SocketInputStream.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 || off + length > b.length) {
if (length == 0) {
return 0;
}
throw new ArrayIndexOutOfBoundsException();
}
 
boolean gotReset = false;
 
// acquire file descriptor and do the read
FileDescriptor fd = impl.acquireFD();
try {
n = socketRead(fd, b, off, length, timeout);//native函数
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);//native function, here reads data from kernel mode to array b
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;
}
   The second piece of code is the general implementation of NIO
sun.nio.ch.DatagramChannelImpl.receive
private int receive(FileDescriptor fd, ByteBuffer dst)
        throws IOException
    {
        int pos = dst.position();
        int lim = dst.limit();
        assert (pos <= lim);
        int rem = (pos <= lim ? lim - pos : 0);
        if (dst instanceof DirectBuffer && rem > 0)
            return receiveIntoNativeBuffer(fd, dst, rem, pos);

        // Substitute a native buffer. If the supplied buffer is empty
        // we must instead use a nonempty buffer, otherwise the call
        // will not block waiting for a datagram on some platforms.
        int newSize = Math.max(rem, 1);
        ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);//Apply for a buffer block of newSize size
        try {
            int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);//Data is read into the buffer, the buffer can be marked, manipulated pointers, etc.
            bb.flip();
            if (n > 0 && rem > 0)
                dst.put(bb);
            return n;
        } finally {
            Util.releaseTemporaryDirectBuffer(bb);
        }
    }
   It can be seen that in the first piece of code, a considerable length of data is obtained from the native function at one time, and then the data is directly manipulated. In the second piece of code, Util.getTemporaryDirectBuffer(newSize); applies for a piece of off-heap memory, The data read each time is placed in this memory, and then the memory is operated. Generally speaking, the advantage of cache-oriented over stream-oriented is that it increases the flexibility of processing data, and of course it also increases the complexity of operations, such as whether it will overwrite previous data when more data is fetched. 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326327940&siteId=291194637