开发者

Java: Proper Network IO handling?

The problem I am having is that when I use an InputStream to read bytes, it blocks until the connection is finished. EG:

        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[20000];
        while (is.read(buffer) != -1) {
            System.out.println("reading");
        }
        System.out.println("socket read");

"socket read" doesn't print out until the FYN packet is actually recieved, thus closing the connection. What is the proper w开发者_高级运维ay to receive all the bytes in without blocking and waiting for the connection to drop?


Take a look at java.nio which has non-blocking IO support.


Reading till you get -1 means that you want to read until EOS. If you don't want to read until EOS, don't loop till the -1: stop sooner. The question is 'when?'

If you want to read a complete 'message' and no more, you must send the message in such a way that the reader can find its end: for example, a type-length-value protocol, or more simply a size word before each message, or a self-describing protocol such as XML.


With traditional sockets the point is that usually you do want them to block: what you do when logically you don't want your program to block is you put your reading/writing code in another thread, so that the separate read/write thread blocks, but not your whole program.

Failing that, you can use the available() method to see if there is actually any input available before reading. But then you need to be careful not to sit in a loop burning CPU by constantly calling available().

Edit: if the problem is that you're happy to block until the bytes have arrived, but not until the connection has dropped (and that is what is happeningh), then you need to make the client at the other end call flush() on its output stream after it has sent the bytes.


Try this:

        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[20000];
        int bytesRead;
        do {
            System.out.println("reading");
            bytesRead = is.read(buffer);
        }
        while (is.available() > 0 && bytesRead != -1);
        System.out.println("socket read");

More info: https://docs.oracle.com/javase/1.5.0/docs/api/java/io/InputStream.html#available()


Example taken from exampledepot on java.nio

// Create a direct buffer to get bytes from socket.
// Direct buffers should be long-lived and be reused as much as possible.
ByteBuffer buf = ByteBuffer.allocateDirect(1024);

try {
    // Clear the buffer and read bytes from socket
    buf.clear();
    int numBytesRead = socketChannel.read(buf);

    if (numBytesRead == -1) {
        // No more bytes can be read from the channel
        socketChannel.close();
    } else {
        // To read the bytes, flip the buffer
        buf.flip();

        // Read the bytes from the buffer ...;
        // see Getting Bytes from a ByteBuffer
    }
} catch (IOException e) {
    // Connection may have been closed
}

Be sure to understand buffer flipping because it causes a lot of headache. Basically, you have to reverse your buffer to read from it. If you are to reuse that buffer to have the socket to write in it, you have to flip it again. However clear() resets the buffer direction.


the code is probably not doing what you think it does. read(buffer) returns the number of bytes it read, in other words: it is not guaranties to fill up your buffer anyway. See DataInputStream.readFully() for code that fill up the entire array:

or you can use this functions (which are based on DataInputStream.readFully()) :

public final void readFully(InputStream in, byte b[]) throws IOException
{
    readFully(in, b, 0, b.length);
}

public final void readFully(InputStream in, byte b[], int off, int len) throws IOException
{
    if (len < 0) throw new IndexOutOfBoundsException();
    int n = 0;
    while (n < len)
    {
        int count = in.read(b, off + n, len - n);
        if (count < 0) throw new EOFException();
        n += count;
    }
}

Your code would look like:

InputStream is = socket.getInputStream();
byte[] buffer = new byte[20000];
readFully(is, buffer);
System.out.println("socket read");
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜